为什么 select() 会因 EINTR errno 而失败?

Wil*_*mKF 5 c++ select eintr infinite-loop

我有一个包含此功能的 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Bas*_*tch 1

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

retry:
struct timeout timeoutcopy = timeout;
const int selectReturn
  = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, &timeoutcopy);
Run Code Online (Sandbox Code Playgroud)

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

顺便说一句,我建议使用poll(2)代替select(因为poll它对 C10K 问题更友好)

顺便说一句,即使没有注册的信号处理程序,EINTR也会发生在任何信号上(请参阅signal(7) )。

您可能会用来strace了解程序的整体行为。

  • 这如何导致他看到的“EINTR”行为? (3认同)