我目前正在添加从创建的 sockfdsaccept到具有以下事件的 epoll 实例:
const int EVENTS = (
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
一旦触发事件,我将其传递给处理程序线程,读取并重新启用 sockfdepoll_ctl
具有相同的标志。但是,我只收到EPOLLIN
活动一次。另外,如果我在收到第一个事件后随时终止客户端,我也不会收到挂断事件。通过阅读手册页,我认为我理解了 EdgeTriggered 和 OneShot 的正确方法。
下面是我正在使用的过程的一些伪代码:
const int EVENTS = (
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
void event_loop()
{
struct epoll_event event;
struct epoll_event *events;
events = calloc(100, sizeof event);
while (1)
{
int x;
int num_events = epoll_wait(epfd, events, 100, -1);
for (x = 0; x < num_events; x++)
{
another_thread(fd);
}
}
}
void another_thread(int fd)
{
// Read stuff until EAGAIN
struct epoll_event event;
event.data.fd = fd;
event.events = EVENTS;
epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
}
当我做的时候EPOLL_CTL_MOD
操作时,我没有收到任何错误,但从未收到其他事件的通知。如果我在第一个事件之后重复读取循环,它将读取客户端发送的所有后续数据,因此我知道数据正在传入并且 fd 仍然打开并工作。
从检查strace
,线程是从创建的clone并有旗帜CLONE_FILES
,所以所有线程共享同一个fd表。
从单独的线程重新启用 fd 来读取事件的正确方法是什么?