如果在一个单独的线程中closures(2)文件描述符,select(2)会做什么?

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

从一些粗略的testing,它确实马上返回。 我怀疑结果是(a)它仍然在等待数据,但如果你真的试图读取它,你会得到EBADF(可能 – 有潜在的种族)或(b)它假装像文件描述符从来没有被传入。如果后一种情况是真的,传入一个没有超时的fd会导致死锁,如果它被closures。

从另外一些调查来看,dwc和Bothie都是对的。

Bothie对这个问题的回答归结为:这是不确定的行为。 这并不意味着它是不可预测的,但不同的操作系统会有不同的做法。 在这种情况下,看起来像Solaris和HP-UX这样的系统从select(2)返回,但是Linux从2001年开始并没有将这篇文章基于linux-kernel邮件列表 。

linux-kernel邮件列表中的参数本质上是未定义(和破坏)的行为依赖。 在Linux的情况下,在文件描述符上调用close(2)有效地减少引用计数。 由于还有一个select(2)调用并且引用了它,所以fd将保持打开并等待输入,直到select(2)返回。 这基本上是dwc的答案 。 你将得到一个文件描述符的事件,然后它将被关闭。 试图读取它将导致一个EBADF,假设fd没有被回收。 (MarkR在他的回答中提出的一个问题,尽管我认为在大多数情况下可以通过适当的同步来避免)。

所以谢谢大家的帮助。

我希望它会像文件结束已经到达一样,也就是说,它将返回文件描述符显示为准备好,但随后尝试读取它将返回“坏的文件描述符”。

话虽如此,无论如何,这样做是非常糟糕的做法,因为您总是有潜在的竞争条件,因为另一个线程在另一个线程关闭之后会立即打开具有相同编号的另一个文件描述符,那么选择线程将会结束等着错了。

一旦你关闭了一个文件,它的编号就可以重用,并且可以在下一次调用open(),socket()等时被重用,即使是通过另一个线程。 所以你真的需要避免这种事情。

选择系统调用是等待文件描述符改变状态的一种方式,而程序没有其他的事情要做。 主要用于服务器应用程序,这些应用程序打开一堆文件描述符,然后等待它们执行任何操作(接受新的连接,读取请求或发送响应)。 这些文件描述符将以非阻塞的io模式打开,以便服务器进程在任何时候都不会挂在系统调用中。

这也意味着,不需要单独的线程,因为所有可以在线程中完成的工作都可以在选择调用之前完成。 如果工作需要很长时间,可能会被中断,选择使用timeout = {0,0}调用,文件描述符被处理,之后工作正在恢复。

现在,您在另一个线程中关闭文件描述符。 为什么你有这个额外的线程,为什么要关闭文件描述符?

POSIX标准没有提供任何提示,在这种情况下会发生什么,所以你在做什么是未定义的行为。 预计在不同的操作系统之间,甚至同一个操作系统的版本之间,结果会有很大的不同。

问候,博多

这是有点混淆你问…

选择()应该返回一个“有趣”的变化。 如果close()仅仅减少了引用计数,并且文件仍然处于打开状态,那么select()就没有任何理由被唤醒。

如果另一个线程在唯一打开的描述符上执行close(),那么它会变得更有趣,但是我需要查看代码的简单版本,以查看是否有错误。