5

我有一个包含此功能的 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 是一个套接字。

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

4

1 回答 1

1

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

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

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

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

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

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

于 2015-02-11T20:00:57.010 回答