【问题标题】:triggering kevent by force强制触发 kevent
【发布时间】:2011-03-22 05:59:06
【问题描述】:

我在 OS X 中使用 kqueue 进行套接字同步。我可以注册一个感兴趣的事件,如下所示:

struct kevent change;
EV_SET(&change, connected_socket, EVFILT_READ, EV_ADD, 0, NULL, NULL);
kevent(k_queue_, &change, 1, NULL, 0, NULL);

问题是,有没有办法强制触发这个事件,让等待的 kevent 调用返回?

【问题讨论】:

    标签: macos sockets freebsd kqueue


    【解决方案1】:

    除了将数据自然写入到套接字的另一端之外的一些可能性:)

    • shutdown(2) 该套接字的读取端 - 您将在 flags 中获得 EV_EOF(愚蠢),
    • 使用超时参数并调用相同的处理函数,
    • 当您需要中断等待时,请使用self-pipe trick

    我的问题是:你为什么需要这个?

    编辑:

    如果我正确理解您的 cmets,您正在寻找一种方法来解决写入事件的边缘触发行为 (EV_CLEAR)。我相信这样做的正确方法是当您在传出队列中没有任何内容时从EVFILT_WRITE 取消注册您的套接字,然后在有数据要发送时再次重新注册它.它需要更多的工作,但这就是它的工作方式,并且您不需要任何额外的系统调用,因为kevent(2) 接受更改和结果。看看libevent,看看它是如何处理这类事情的。而且您使用的是非阻塞套接字,对吧?

    【讨论】:

    • 谢谢你的回答,尼古拉。我正在编写一个应用程序服务器,我不想阻止任何线程读取/写入套接字。阅读很简单。有一个 io 线程,只要有东西进入套接字,它就会从 kevent 中唤醒并读取数据,以便其他工作线程可以处理它。
    • 但是写入更复杂,因为即使 io 线程因为套接字上有一些可用空间而被唤醒,输出数据队列中也可能没有任何内容可写入。因此,每当我们向传出数据队列写入内容时,我想让 io 线程强制从 kevent 返回。这有意义吗?
    • @Kay,我在答案中添加了更多内容。
    • 哦,你是对的。我有点困惑。 EVFILT_WRITE 默认是边沿触发还是电平触发?如果我正确理解您的评论,默认情况下它是级别触发的,当套接字为空且传出队列也为空时,它将继续唤醒并消耗 CPU,因此我应该通过设置 EV_CLEAR 标志显式使其边缘触发做你说的把戏。这是正确的吗?
    • 是的,正确的。默认情况下,一切都是电平触发的,如select(2)poll(2)。祝你好运!
    【解决方案2】:

    我会推荐一个稍微不同的解决方案。

    将另一个注册事件添加到 kqueue。特别是 EVFILT_USER。

    您可以使用它来触发您想要唤醒 kevent() 线程的任何行为,而不会让代码看起来很奇怪或难以维护。

    OSX 源码对其进行了真正的粗略测试

    http://www.opensource.apple.com/source/xnu/xnu-1699.24.23/tools/tests/xnu_quick_test/kqueue_tests.c

    【讨论】:

    • +1 我喜欢!我将基于 OSX poll 的解决方案转换为使用 kqueue,因为我可以正确支持用户事件,而不是使用 self-pipe 技巧
    【解决方案3】:

    OSX 10.6 和 FreeBSD 8.1 添加了对EVFILT_USER 的支持,我们可以使用它来从另一个线程唤醒事件循环。

    请注意,如果您使用它来实现自己的条件和 timedwait,您仍然需要锁定以避免竞争条件,如 this excellent answer 中所述。

    完整代码示例请参见我的其他答案:https://stackoverflow.com/a/31174803/432

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多