一尘不染

具有边缘触发事件的epoll

linux

epoll的手册页上有一个触发边的示例代码,如下所示:

for (;;) {
    nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
    if (nfds == -1) {
        perror("epoll_pwait");
        exit(EXIT_FAILURE);
    }

    for (n = 0; n < nfds; ++n) {
        if (events[n].data.fd == listen_sock) {
            conn_sock = accept(listen_sock,
                        (struct sockaddr *) &local, &addrlen);
            if (conn_sock == -1) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            setnonblocking(conn_sock);
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = conn_sock;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                    &ev) == -1) {
                perror("epoll_ctl: conn_sock");
                exit(EXIT_FAILURE);
            }
        } else {
            do_use_fd(events[n].data.fd);
        }
    }
}

在do_use_fd函数中,我在while循环中调用非阻塞recv直到EAGAIN为止,示例代码运行良好。

我对此示例代码有一个疑问,假设现在我有50个套接字客户端连接,突然有10个客户端同时写入数据,因此epoll_wait()将返回10,然后转到for循环:

for (n = 0; n < nfds; ++n)

它将调用 do_use_fd(events[n].data.fd); 这10个客户端,假设n = 5完成,并且n =
6尚未完成,则在所有这10个事件都完成之后,事件n = 3的文件描述突然接收到新数据,并返回epoll_wait
,该事件是否会通知我,有一个客户端需要读取新数据?否则我会错过它,因为当事件发生时,代码不在epoll_wait中!


阅读 304

收藏
2020-06-07

共1个答案

一尘不染

只要您一直阅读直到遇到EAGAIN错误,您下次调用时都会得到该事件epoll_wait

仅当在空值和非空值之间(或的完整和不完整EPOLLOUT)之间发生更改时才触发该事件,但是该状态将保持不变,直到通过发送事件为止epoll_wait

有点相关的注释:如果您注册EPOLLINEPOLLOUT事件,并且假设您从未填满发送缓冲区,那么每次触发EPOLLOUT返回的事件中,您仍然会获得标志集-
请参见https://lkml.org/lkml/2011 /
11/17/234了解更多详细说明。epoll_wait``EPOLLIN

最后,边沿触发模式的确切行为实际上取决于所使用的套接字类型,并且在任何地方都没有实际记载。我前段时间做了一些测试,并在这里记录了我的发现:http
:
//cmeerw.org/blog/753.html#753-简而言之,对于数据报套接字,您可能会收到比预期更多的事件。

2020-06-07