【问题标题】:When to rearm epoll with edge mode & oneshot?何时使用边缘模式和 oneshot 重新武装 epoll?
【发布时间】:2021-12-21 12:21:41
【问题描述】:

我正在为套接字编写一个协程包装器,作为协程用例的演示,我正在为如何安全地使用 epoll(不引入竞争条件)而苦苦挣扎。

我已经知道我必须使用边缘模式EPOLLETEPOLLONESHOT。但现在我不确定什么时候应该重新启动插座。

我应该在调用非阻塞操作之前还是之后重新武装?我想确保我既不会错过活动,也不会收到幻影。

// epoll & socket setup

int ret;

ret = epoll_ctl(epoll_, EPOLL_CTL_MOD, ...); // rearm here
//...
ret = read(...);
//...
ret = epoll_ctl(epoll_, EPOL_CTL_MOD, ...); // or here?

int ret = epoll_wait(...);

【问题讨论】:

    标签: c linux epoll


    【解决方案1】:

    我应该在调用非阻塞操作之前还是之后重新武装?

    从技术上讲,之后,但并不是那么简单。

    不管EPOLLONESHOT,一旦你收到一个边沿触发的事件,表明给定文件描述符的读准备就绪,你必须考虑到FD继续准备好直到它上面的read()失败并设置了errnoEAGAIN(因此文件必须处于非阻塞模式)。在这些读取过程中,您可能会使用一个read() 读取所有剩余字节,但随后更多字节在下一个之前到达。在这种情况下,如果 FD 仍处于布防状态,则它的新事件将排队(或与该 FD 的另一个事件合并,视情况而定)。这种情况可能会导致您收到一个事件,而实际上 FD 还没有准备好。

    您应该考虑只接受那些“幻影”事件。由于您的文件将处于非阻塞模式,因此它们不会导致不必要的停顿,只需进行一些额外的工作。你的代码会更简单。但是,如果您确实使用EPOLLONESHOT 来避免接收幻像事件,那么在您确定它未准备好之前,您不得重新武装FD(通过read 失败并返回EAGAIN),否则您将无法达到目的。

    因此,完整的答案是在确定 FD 未就绪之后。这将需要至少两个read()s,甚至更多。如果文件在最后一次读取之后和重新加载之前准备好,那么重新加载应该会导致适当的事件排队。

    【讨论】:

    • 好的,只是一个小小的说明。如果我之后重新武装,我能保证收到事件吗?还是有机会错过?
    • @ŠimonTóth,我的理解是,如果在您重新武装时 FD 已经准备好,那么会立即触发一个事件。文档对此不是很清楚,但 epoll 否则会非常糟糕。
    • 但是,请再次考虑不要使用EPOLLONESHOT
    • 是的,文档很烂,这就是我发布问题的原因。我会去相信这个解释,确实会在没有EPOLLONESHOT 的情况下做EPOLLET
    猜你喜欢
    • 1970-01-01
    • 2016-07-08
    • 2018-12-06
    • 2014-10-14
    • 2013-01-25
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多