Grand Central Dispatch (GCD) 调度源标志

11

我最近从使用kqueue切换到GCD调度源来监控文件更改。这样做效果很好,API也变得简单了许多。我在这里记录了我的转换过程。唯一的问题是现在我无法像在kqueue中那样访问事件的标志。例如,使用kqueue,我可以通过以下方式检查文件是否已删除、重命名或更改其属性:

struct kevent event;

...

if(event.flag & EV_DELETE)
{
    printf("File was deleted\n");
}

这个API在GCD中不可用吗?还是我需要为每个我想要监听的标志设置调度源?或者最好使用kqueue,因为它提供了更大的事件可见性。


3
我其实没有真正阅读你的问题,但我点了个赞,这样你的声望就能达到1337了。好的,我现在会去读一下它。 - morningstar
2个回答

9

我在并发编程指南中找到了答案。我最初查看了GCD参考资料但没有运气。指南中相关的一行是:

对于监视文件系统活动的描述符调度源,此函数返回表示发生事件类型的常量。有关常量的列表,请参见dispatch_source_vnode_flags_t枚举类型。

以下是如何使用它的示例。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
int fildes = open("path/to/some/file", O_EVTONLY);
__block dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fildes, 
                                                  DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
                                                  queue);
dispatch_source_set_event_handler(source, ^
{
    unsigned long flags = dispatch_source_get_mask(source);
    if(flags & DISPATCH_VNODE_DELETE)
        printf("DISPATCH_VNODE_DELETE\n");
    if(flags & DISPATCH_VNODE_WRITE)
        printf("DISPATCH_VNODE_WRITE\n");
    if(flags & DISPATCH_VNODE_EXTEND)
        printf("DISPATCH_VNODE_EXTEND\n");
    if(flags & DISPATCH_VNODE_ATTRIB)
        printf("DISPATCH_VNODE_ATTRIB\n");
    if(flags & DISPATCH_VNODE_LINK)
        printf("DISPATCH_VNODE_LINK\n");
    if(flags & DISPATCH_VNODE_RENAME)
        printf("DISPATCH_VNODE_RENAME\n");
    if(flags & DISPATCH_VNODE_REVOKE)
        printf("DISPATCH_VNODE_REVOKE\n");
});
dispatch_source_set_cancel_handler(source, ^(void) 
{
    close(fildes);
});
dispatch_resume(source);

1
谢谢,太棒了。我使用了你博客文章中的那个。不过,你应该把第17行从[blockSelf watchStyleSheet:path];改为[blockSelf watchConfigFile:path]; - Stéphane Bruckert
source 没有被赋值,因此它不需要是 __block - user102008
还有,应该使用dispatch_source_get_data而不是dispatch_source_get_mask。使用别人的代码却不真正理解它的荣耀... - Mojo66

5
您可以将*dispatch_source_get_mask(source)*更改为*dispatch_source_get_data(source)*,因为dispatch_source_get_mask(source)返回的是在处理程序创建时传递的所有标志,而不是生成的事件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接