Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 带边缘触发和oneshot的Epoll仅报告一次_C_Linux_Epoll - Fatal编程技术网

C 带边缘触发和oneshot的Epoll仅报告一次

C 带边缘触发和oneshot的Epoll仅报告一次,c,linux,epoll,C,Linux,Epoll,我当前正在将从创建的SOCKFD添加到具有以下事件的epoll实例: const int EVENTS = ( EPOLLET | EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLERR | EPOLLHUP); 触发事件后,我将其传递给处理程序线程,读取sockfd,然后使用相同的标志通过epoll\u ctl重新启用它。但是,我只收到一次EPOLLIN事件。此外,如果我在收到第一个事件后随时终止客户端,我

我当前正在将从创建的SOCKFD添加到具有以下事件的epoll实例:

const int EVENTS = (
    EPOLLET |
    EPOLLIN |
    EPOLLRDHUP |
    EPOLLONESHOT |
    EPOLLERR |
    EPOLLHUP);
触发事件后,我将其传递给处理程序线程,读取sockfd,然后使用相同的标志通过
epoll\u 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);
}
const int事件=(
埃波尔特|
埃波林|
埃波尔德胡普|
埃波洛内斯肖|
埃波尔|
EPOLLHUP);
无效事件_循环()
{
结构epoll_事件;
结构epoll_事件*事件;
events=calloc(100,事件大小);
而(1)
{
int x;
int num_events=epoll_wait(epfd,events,100,-1);
对于(x=0;x
当我执行
EPOLL\u CTL\u MOD
操作时,我没有收到任何错误,但从未收到其他事件的通知。如果我在第一个事件之后让read循环保持在repeat状态,它将读取客户端发送的所有后续数据,因此我知道数据正在进入,并且fd仍然打开并工作

通过检查
strace
,线程是从创建的,并且具有标记
CLONE\u FILES
,因此所有线程共享相同的fd表

为从单独线程读取事件重新启用fd的正确方法是什么

但是,我只收到一次EPOLLIN事件。此外,如果我在收到第一个事件后随时终止客户端,我也不会收到挂断事件

epoll_ctl(2)的手册页上说:

epolonneshot(从Linux 2.6.2开始) 设置关联文件描述符的一次性行为。 这意味着,在使用 epoll_wait(2)关联的文件描述符在内部 已禁用,epoll不会报告任何其他事件 接口。用户必须使用epoll\u ctl\u MOD调用epoll\u ctl() 使用新的事件掩码重新排列文件描述符

在您的情况下,当您获得第一个事件时,epoll将禁用sockfd。 当您使用
EPOLL\u CTL\u MOD
重新启用sockfd时,它将在重新注册后通知内核接收到的所有事件。因此,第一次通知和重新注册之间的任何事件都将丢失。这可能是不获取任何挂起事件或数据的原因

从事件中删除
epolonneshot
将更正您的代码,最终您不需要重新启用sockfd


由于您使用的是
EPOLLET
,因此不会有任何性能问题。

事实并非如此,我在客户端代码中有3-5秒的巨大延迟,只是为了测试这种情况,我看到在客户端尝试再次发送之前,fd已经准备好了日志消息。删除“一次性”标志无效:(您是否给客户端3-5秒的延迟时间来检查您是否收到“epolldhup”事件,或者只是两次发送之间的延迟?两次发送之间的延迟。由于EPOLLET,您将在注册事件的状态发生变化时收到通知。在EPOLLIN | EPOLLET情况下,您将在读取缓冲区中出现新数据时收到通知。当执行第一次发送时,epoll将为其返回一个事件,epoll_wait将成功返回,您的线程将读取数据。同时,主线程将再次转到epoll_wait并等待某个事件。3-5秒后,将执行第二次发送,epoll_wait将在socketfd上返回相同的读取事件。这就是为什么您将获取多个读取事件标记。我想你误读了这个问题,我只收到一个通知。MCVE会有很大帮助。例如,伪代码没有解释事件循环和处理程序线程之间的切换。这里有三个“移动部分”:EPOLLET(你试过没有此标记的代码吗?),epolonneshot和多线程。因此,诊断真正的问题相对来说是困难的。这个问题为您解决了吗?我正在构建类似的东西,我很好奇您是否能让它工作?我也很好奇,经过这么长时间。也许这就像在
另一个线程()中切换操作顺序一样简单。
:执行在调用
epoll\u ctl()
以重新激活边缘触发器后,“在EAGAIN之前读取内容”。否则存在争用条件:新数据可能会在从I/O
Read()
操作返回的EAGAIN与调用
epoll\u ctl()之间进入读取缓冲区
,这将丢失边缘触发器。@arayq2这是修复方法。基本上,在开始读取之前重置事件中的所有标志,以避免在读取时丢失事件中的数据。