我目前正在将一个从accept创建的sockfds添加到epoll实例中,其中包含以下事件:
const int EVENTS = (
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
触发事件后,我将其传递给处理程序线程,读取然后通过epoll_ctl使用相同的标志重新启用sockfd.但是,我只收到一次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的正确方法是什么? 解决方法:
However, I only receive the EPOLLIN event one time. Also, if I kill the client anytime after the first event is received, I do not get hangup events either.
epoll_ctl(2)的手册页说:
EPOLLONESHOT (since Linux 2.6.2)
Sets the one-shot behavior for the associated file descriptor.
This means that after an event is pulled out with
epoll_wait(2) the associated file descriptor is internally
disabled and no other events will be reported by the epoll
interface. The user must call epoll_ctl() with EPOLL_CTL_MOD
to rearm the file descriptor with a new event mask.
在你的情况下,当你得到第一个事件时,epoll会禁用你的sockfd. 当您使用EPOLL_CTL_MOD重新启用sockfd时,它将通知重新注册后内核接收的所有事件.因此,首次通知和重新注册之间的任何事件都将丢失.这可能是没有获取任何挂起事件或数据的原因.
从事件中删除EPOLLONESHOT将更正您的代码,最终您也不需要重新启用sockfd.
由于您使用的是EPOLLET,因此也不存在任何性能问题. 来源:https://www./content-4-317751.html
|