select() 在长时间运行后立即超时 (C++)

Posted

技术标签:

【中文标题】select() 在长时间运行后立即超时 (C++)【英文标题】:select() times out immediately after long runtime (C++) 【发布时间】:2011-07-27 22:37:39 【问题描述】:

大多数情况下,这段代码运行良好。但有时当可执行文件运行了一段时间后,select() 似乎立即超时,然后进入一个奇怪的状态,它不断被调用,立即超时,一遍又一遍。然后必须从外面杀死它。

我的猜测是标准输入超时更改的方式有问题 - 这就是 select 阻塞的原因。

在 *** 上环顾四周,大多数人的 select() 问题似乎都可以通过确保每次都使用宏(FD_ZERO 和 FD_SET)重置并使用正确的初始参数进行选择来解决。我不认为这些是这里的问题。

int            rc     = 0;
fd_set         fdset;
struct timeval timeout;

// -- clear out the response -- //
readValue = "";

// -- set the timeout -- //
timeout.tv_sec = passedInTimeout;  // 5 seconds
timeout.tv_usec = 0;

// -- indicate which file descriptors to select from -- //
FD_ZERO(&fdset);
FD_SET(passedInFileDescriptor, &fdset); //passedInFileDescriptor = 0

// -- perform the selection operation, with timeout -- //
rc = select(1, &fdset, NULL, NULL, &timeout);


if (rc == -1)  // -- select failed -- //

    result = TR_ERROR;

else if (rc == 0)  // -- select timed out -- //

    result = TR_TIMEDOUT;

else 

    if (FD_ISSET(mFileDescriptor, &fdset))
    
        if(rc = readData(readValue) <= 0)
        
            result = TR_ERROR;
        
     else 
       result = TR_SUCCESS;
    

【问题讨论】:

你能在rc == 0的情况下添加一些调试代码吗?记录passedInFileDescriptor的值,timeoutFD_ISSET(mFileDescriptor, &amp;fdset)中的字段;如果这个总结的代码是正确的,就会出现一些可疑的事情,你可能需要更多的数据来尝试确定它。 调用 ioctl() 和 tcsetattr() 更改文件描述符的内容。打开文件的公共文件描述符可以在父子之间共享,并且子子可以更改描述符,然后传播到父子。这假设您自己没有进行 ioctl() 或类似的调用。我正在考虑文件的非阻塞行为。 文件描述符是否已关闭或到达eof? 【参考方案1】:

请注意,“选择”的一些实现严格适用于规范: “nfds 是三组中编号最高的文件描述符,加 1”。 因此,您最好将“1”更改为“passedInFileDescriptor+1”作为第一个参数。 我不知道这是否可以解决您的问题,但至少您的代码变得更加......呃......“传统”;)

再见

【讨论】:

谢谢!我修改了它。行为没有改变,但我很高兴更正确。 嗨! “mFileDescriptor”总是等于“passedInFileDescriptor”吗?如果不是真的,可能会发生一些奇怪的事情。例如:如果“mFileDescriptor”错误且“FD_ISSET”成功且“readData() > 0”会发生什么? “结果”在您的代码中未定义,所以......嗯......好吧,我的只是一个提示。再见!【参考方案2】:

在某些操作系统上,timeout 在调用 select 时会被修改以反映未睡觉的时间量。在您的示例中,您似乎没有重复使用 timeout,但请确保您确实在每次调用 select 之前将其重新初始化为 5 秒。

【讨论】:

【参考方案3】:

我遇到了同样的问题,它在 windows 上运行良好,但在 linux 上运行良好,我将 maxfd 设置为最后一个套接字 + 1。它在长时间运行后会定期发生。我在接受时拿起连接,然后第一次调用 select 定期超时。

【讨论】:

【参考方案4】:

看这段代码:

if (FD_ISSET(mFileDescriptor, &fdset))

    if(rc = readData(readValue) <= 0)
    
        result = TR_ERROR;
    
 else  
   result = TR_SUCCESS;

这里有两件事困扰着我:

    如果您的 FD 中没有数据(例如发生错误), FD_ISSET() 将返回 false 并且您的函数返回 TR_SUCCESS!? 你FD_SET(passedInFileDescriptor, &amp;fdset),但检查另一个 值:FD_ISSET(mFileDescriptor, &amp;fdset)。如果 mFileDescriptor != passInFileDescriptor 在某些时候,你会落入我的第一个 假设。

它应该是这样的:

if (FD_ISSET(passedInFileDescriptor, &fdset))

    if(rc = readData(readValue) <= 0)
    
        result = TR_ERROR;
    
    else 
    
        result = TR_SUCCESS;
    

else

    result = TR_ERROR;

没有?

(编辑:另外,this answer 还指出了您使用 select() 的问题是 high_fd 值不好)

另一个编辑:嗯,看起来那些家伙再也没有回来......令人沮丧。

【讨论】:

以上是关于select() 在长时间运行后立即超时 (C++)的主要内容,如果未能解决你的问题,请参考以下文章

长时间运行的 Azure WebJob 失败 - 客户端无法在指定的超时时间内完成操作

长时间运行的后台任务完成后应用程序未挂起

如何在长时间运行的程序中立即确认 Pub/Sub 消息

是啥导致应用程序在后台长时间运行后在恢复时崩溃?

具有长时间运行任务的单独线程中的计时器

超时服务器端长时间运行的请求[重复]