强制触发 kevent

3

我正在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调用将返回?

3个回答

3
除了将数据自然地写入套接字的另一侧外,还有一些可能性:)
  • shutdown(2) 套接字的读端 - 您将在 flags 中得到EV_EOF(傻瓜),
  • 使用超时参数并调用相同的处理函数,
  • 需要打破等待时,请使用自我管道技巧

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

编辑:

如果我正确理解您的评论,您正在寻找一种绕过写入事件的边缘触发行为 (EV_CLEAR) 的方法。我认为正确的做法是在没有队列中的传出数据时从EVFILT_WRITE中注销套接字,然后在有数据要发送时重新注册它。这是有点麻烦,但这就是它的工作原理,而且由于kevent(2)接受更改和结果,您不需要任何额外的系统调用。看看libevent如何处理这种情况。你使用非阻塞套接字,对吗?


谢谢你的回答,Nikolai。我正在编写一个应用服务器,我不想阻塞任何线程来读取/写入套接字。读取很简单。有一个io线程,每当套接字中有数据进来时,它就会从kevent中唤醒并读取数据,以便其他工作线程可以处理它。 - Kay
但是编写代码更加复杂,因为即使IO线程因套接字上有可用空间而唤醒,也可能没有任何内容可以写入传出数据队列。因此,我希望每当我们向传出数据队列中写入内容时,都能强制使IO线程从kevent返回。这样做有意义吗? - Kay
@Kay,我在答案中添加了更多内容。 - Nikolai Fetissov
哦,你说得对。我有点困惑。EVFILT_WRITE 默认是边缘触发还是电平触发?如果我正确理解了你的评论,它默认是电平触发的,并且当套接字为空且传出队列也为空时,它将不断唤醒并消耗 CPU,因此我应该通过设置 EV_CLEAR 标志来显式地使其成为边缘触发,并执行你所说的技巧。这样正确吗? - Kay
是的,正确的。默认情况下,所有内容都是电平触发的,就像select(2)poll(2)一样。祝你好运! - Nikolai Fetissov

2

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

请注意,如果您使用此功能来实现自己的条件和定时等待,您仍然需要锁以避免竞争条件,如这个优秀答案所解释的。

查看我的其他答案,获取完整的代码示例:https://dev59.com/vmgu5IYBdhLWcg3wZma8#31174803


2

+1 我喜欢!现在我将把我的基于OSX的“poll”解决方案转换为使用“kqueue”,因为我可以拥有得到适当支持的用户事件,而不是使用“self-pipe trick”。 - trojanfoe

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