为什么select()与EINTR errno一起失败?

时间:2015-02-11 19:59:08

标签: c++ select infinite-loop eintr

我有一个包含此功能的C ++应用程序:

int
mySelect(const int fdMaxPlus1,
         fd_set *readFDset,
         fd_set *writeFDset,
         struct timeval *timeout)
{
 retry:
  const int selectReturn
    = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, timeout);

  if (selectReturn < 0 && EINTR == errno) {
    // Interrupted system call, such as for profiling signal, try again.
    goto retry;
  }

  return selectReturn;
}

通常,这段代码工作得很好,但是,在一个实例中,我看到它进入了一个无限循环,其中select()使EINTR errno代码失败。在这种情况下,调用者将超时设置为零秒和零微秒,这意味着不要等待并立即返回select()结果。我认为EINTR仅在信号处理程序发生时才会发生,为什么我会一遍又一遍地使用信号处理程序(超过12小时)?这是Centos 5.一旦我把它放到调试器中看看发生了什么,代码在几次迭代后没有EINTR就返回了。请注意,正在检查的fd是套接字。

我可以为上面的代码添加重试限制,但我想先了解一下发生了什么。

1 个答案:

答案 0 :(得分:1)

在Linux上,select(2)可能会修改 timeout 参数(通过地址传递)。所以你应该在通话后复制它。

retry:
struct timeout timeoutcopy = timeout;
const int selectReturn
  = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, &timeoutcopy);

(在您的代码中,您的timeout在经过几次甚至是第一次迭代后可能为零或非常小)

顺便说一句,我建议使用poll(2)而不是select(因为poll更多是C10K问题友好)

BTW,EINTR发生在任何信号上(见signal(7)),即使没有注册信号处理程序。

您可以使用strace来了解程序的整体行为。