当select(2)
函数正在监视读取的文件描述符被另一个线程关闭时,它的行为是什么?
从一些粗略的测试中,它确实立即返回。我怀疑结果要么是(a)它仍然继续等待数据,但如果你真的试图从它读取你会得到EBADF(可能 - 有一个潜在的竞赛)或(b)它假装好像文件描述符从未传入。如果后一种情况属实,传入一个没有超时的fd将导致死锁,如果它被关闭。
答案 0 :(得分:21)
从一些额外的调查来看,似乎dwc和bothie都是对的。
bothie's answer问题归结为:它是未定义的行为。这并不意味着它必然是不可预测的,但不同的操作系统会以不同的方式做到这一点。在这种情况下,Solaris和HP-UX等系统似乎从select(2)
返回,但Linux从2001年开始不基于this post to the linux-kernel mailing list。
linux-kernel邮件列表中的参数基本上是依赖于未定义(和破坏)的行为。在Linux的情况下,在文件描述符上调用close(2)
会有效地减少对它的引用计数。由于select(2)
调用也引用了它,因此fd将保持打开并等待输入,直到select(2)
返回。这基本上是dwc's answer。您将在文件描述符上获得一个事件,然后它将被关闭。尝试从中读取将导致EBADF,假设fd尚未被回收。 (MarkR在his answer中提出的一个问题,虽然我认为在大多数情况下通过适当的同步可能是可以避免的。)
非常感谢大家的帮助。
答案 1 :(得分:6)
我希望它的行为就好像已经到达文件结尾一样,也就是说,它将返回文件描述符显示为就绪,但任何后续读取它的尝试都会返回“错误的文件描述符”
话虽如此,这样做非常糟糕,因为你总是有潜在的竞争条件,因为另一个文件描述符具有相同的数字,可以由另一个线程紧接着另一个线程打开第二个关闭它,然后选择线程将最终等待错误的。
一旦关闭文件,其编号就可以重用,并且可以在下次调用open(),socket()等时重用,即使是另一个线程也是如此。所以你真的,真的需要避免这种事情。
答案 2 :(得分:5)
select系统调用是一种等待文件desctriptors改变状态的方法,而程序没有任何其他操作。主要用于服务器应用程序,它打开一堆文件描述符,然后等待它们做任何事情(接受新连接,读取请求或发送响应)。这些文件描述符将以非阻塞io模式打开,这样服务器进程就不会在系统调用中挂起。
这另外意味着,不需要单独的线程,因为可以在线程中完成的所有工作也可以在select调用之前完成。如果工作需要很长时间,而不是可以中断,则选择使用timeout = {0,0}进行调用,处理文件描述符,然后恢复工作。
现在,您在另一个线程中关闭文件描述符。为什么你有这个额外的线程,为什么它会关闭文件描述符?
POSIX标准没有提供任何提示,在这种情况下会发生什么,所以你所做的是未定义的行为。期望不同操作系统之间的结果会有很大差异,甚至在相同操作系统的版本之间也是如此。
此致,Bodo
答案 3 :(得分:2)
你问的问题有点令人困惑......
Select()应该返回“有趣”的变化。如果close()只是递减引用计数并且文件仍然打开以便在某处写入,那么select()就没有理由被唤醒。
如果另一个线程在唯一的开放描述符上关闭(),那么它会变得更有趣,但是我需要看一个简单的代码版本,看看是不是真的错了。