【问题标题】:poll(2) doesn't empty the event queuepoll(2) 不会清空事件队列
【发布时间】:2010-06-11 08:01:58
【问题描述】:

我使用 Linux 作为我的编程平台。我正在使用poll(2) 来了解我的设备是否正在触发事件。

poll的第一次调用就ok了;它阻塞并等待事件发生。但是在第二次poll函数调用中,它会返回;但它捕获了事件。下面是我的代码。

ret = poll( fds, 1, 2000); //2 secs timeout

if( fds[0].revents & POLLIN && ret > 0)
{
   printf("event occur\n");
}

似乎队列/缓冲区不为空。我只是假设。

你认为是什么问题?

谢谢。

【问题讨论】:

    标签: linux


    【解决方案1】:

    显然,如果您正在轮询传入的数据,您应该使用可用数据(调用 read()),否则它将仍然存在并且 poll 将立即返回。对称地,POLLOUT 确实不需要任何操作,但您通常希望尽快调用下一个 write()。因此,根据经验,POLLIN -> 读取,POLLOUT -> 写入。

    您还应该在再次调用 poll 之前重置 pollfd 结构。

    fds[0].fd = sck;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    ret = poll( fds, 1, 2000); //2 secs timeout
    
    if( fds[0].revents & POLLIN && ret > 0)
    {
       printf("event occur\n");
    }
    

    如果您不每次都重置它,之前调用的垃圾可能会改变轮询行为(嗯,不是真的,这只是一个可移植性问题)。

    在生产代码中,您还必须检查返回值,因为轮询可能因预期事件以外的其他原因(如信号)而被中断。然后你通常想再次调用它而不是读取不可用的数据(作为提醒,轮询返回值是事件数,0 超时,-1 一些错误,其编号在 errno 中)。

    提供给 poll 的文件描述符也可能发生错误。它们不会使 poll 返回错误,但会在该文件描述符的 pollfd 结构的 revent 字段中设置 POLLERR、POLLHUP 或 POLLNVAL。如果设置了这些事件,调用 read 将返回一些您可以检查的错误代码。

    【讨论】:

    • 谢谢。实际上我总是重置结构中的值,我认为最好的解决方案是读取可用数据。
    • 谢谢,但我的 read 函数调用似乎出错了,它似乎返回了一个 -1 值,errno 说参数无效,但我确定参数是正确的。
    • 我添加了几行关于错误检查的内容。如果您的第一次轮询因超时或错误而停止,则最有可能。我通常在每次轮询后使用 switch 语句来管理错误和超时情况,默认情况下是发生某些事件的正常情况。无论如何,如果读取失败,您应该有一个错误。你的文件描述符好吗?可能打开失败,或者不是为了读取,或者文件被关闭了……好吧,不用猜了,检查错误。
    【解决方案2】:

    如果您有一个 POLLIN 事件,这意味着“有数据要读取” - 您是否在再次调用 poll()'ing 之前在您的 fd 上调用了一些 read() 函数?

    【讨论】:

    • 谢谢,但我不需要阅读这些数据。对我来说重要的是有一个事件。你认为我需要读那个吗?有什么办法可以清除缓冲区吗?
    【解决方案3】:

    poll 会在有数据/事件要读取/错误/何时可以写入时为您提供事件。

    如果您收到“有数据要读取”的事件但您没有读取任何内容 - 下次您致电 poll 时仍然会有“数据要读取”并且您收到另一个事件。

    【讨论】:

      【解决方案4】:

      在读取文件描述符之前检查POLLHUPPOLLNVAL 被认为是一种很好的做法。但是,我相信read() 在这种情况下只会失败,除非轮询预期会长时间阻塞的文件描述符,例如调制解调器。在这种情况下,您会挂起(取决于您传递给open() 的内容)。

      你可能不是:

      • 在下一个poll()之前完全读取事件FD,或者,
      • 读取所有可用数据。

      如果您在调用poll() 之前已经初始化了结构pollfd 数组,那么就不应该有任何“垃圾”可言。

      不过,在调用它之前检查并确保有一些值得打扰 read() 的事情可能是一个好主意。

      【讨论】:

      • 谢谢,我读取了一些数据,但读取的数据似乎返回零值,这意味着没有读取数据。
      • @sasayins,FD 是不是类似于调制解调器?你到底在投票什么?
      【解决方案5】:
      1. poll() 返回 0 表示超时或 -1 如果发生错误。另外revents可以检查POLLERR

        if( poll_return == 0 || poll_return == -1 || ((int)recvpoll.revents & POLLERR) ) return 0 ;
        
      2. 如果你通过fork进程打开一个文件描述符,那么关闭之前的文件描述符并打开一个新的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-26
        • 2018-09-18
        相关资源
        最近更新 更多