为什么 select() 不尊重超时,尤其是在多线程中

问题描述 投票:0回答:1

我们有客户端应用程序来侦听 UDP 多播源并处理传入数据。它是可移植的并且可以在 Windows 和 Linux 上运行。主处理循环使用

select()
等待数据,通常是一两个UDP非阻塞套接字:

while(!stopRequested)
{
   fdset io;
   FD_ZERO(&io);
   FD_SET(sock, &io);

   timeval waitInterval = { 0 };
   waitInterval.tv_usec = 10000; // 10 milliseconds

   int r = select(sock + 1, &io, NULL, NULL, &waitInterval); 
   if(r == 0) // Process timeout
   else // Data or error processing
}

代码运行得很好,但是当没有可用数据时,超时准确性存在问题。 我们测量了在几秒钟的保证空闲(没有发送数据)期间实际花费在

select()
内的时间,分布如下:

<1 usec     : 170 time(s)
<2000 usec  : 1 time(s)
<10000 usec : 11973 time(s)
<12000 usec : 6558 time(s)
<15000 usec : 64 time(s)
<20000 usec : 47 time(s)

没有错误,

select()
总是返回0。所以我们可以看到,有几种情况(170次)
select()
几乎立即返回,而不等待任何超时。

所以问题是为什么在某些情况下不遵守超时? Windows (Win7 x64) 和 Linux (CentOS/RHEL6.0 x64) 都获得了类似的结果。

此外,当使用多线程时,事情变得更糟。当两个线程执行上面的代码时(都为同一个套接字调用

select()
,但
fd_set
waitInterval
是本地对象),
select()
内部的时间分布是这样的(对于每个线程):

<1 usec     : 13800827 time(s)
<10 usec    : 1639 time(s)
<100 usec   : 8660 time(s)
<1000 usec  : 16 time(s)
<12000 usec : 768 time(s)
<15000 usec : 39 time(s)

看起来

select()
几乎从不考虑超时,但在并发调用中立即返回 0。

对于这种令人困惑的行为有什么解释吗?检查了不重新初始化

fd_set
timeout
参数的常见陷阱,但事实并非如此。

c multithreading sockets posix-select
1个回答
0
投票

实际上

select()
没有任何问题,它正确地尊重超时。测量是错误的 - 我测量的不是
select()
调用本身,而是实际检查
fd_set
并在为空时跳过
select()
调用的包装函数。随时<10000 usec aren't related to
select()
致电。

这个问题可能会因为不相关而被删除。

© www.soinside.com 2019 - 2024. All rights reserved.