如果在单独的线程中关闭(2)文件描述符,select(2)会怎么做?

时间:2009-02-12 21:54:19

标签: c linux multithreading posix

select(2)函数正在监视读取的文件描述符被另一个线程关闭时,它的行为是什么?

从一些粗略的测试中,它确实立即返回。我怀疑结果要么是(a)它仍然继续等待数据,但如果你真的试图从它读取你会得到EBADF(可能 - 有一个潜在的竞赛)或(b)它假装好像文件描述符从未传入。如果后一种情况属实,传入一个没有超时的fd将导致死锁,如果它被关闭。

4 个答案:

答案 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()就没有理由被唤醒。

如果另一个线程在唯一的开放描述符上关闭(),那么它会变得更有趣,但是我需要看一个简单的代码版本,看看是不是真的错了。