select(2)
函数在其正在监听的文件描述符被其他线程关闭时会发生什么行为?
经过一些表面测试,它会立即返回。我猜测结果可能是:要么(a)它仍然继续等待数据,但如果您真正尝试从中读取数据,您将获得EBADF(可能存在潜在的竞态条件),要么(b)它会假装好像从未传入该文件描述符。 如果后一种情况是真的,那么在没有超时的情况下传入单个fd会在其关闭时导致死锁。
select(2)
函数在其正在监听的文件描述符被其他线程关闭时会发生什么行为?
经过一些表面测试,它会立即返回。我猜测结果可能是:要么(a)它仍然继续等待数据,但如果您真正尝试从中读取数据,您将获得EBADF(可能存在潜在的竞态条件),要么(b)它会假装好像从未传入该文件描述符。 如果后一种情况是真的,那么在没有超时的情况下传入单个fd会在其关闭时导致死锁。
经过进一步调查,看起来bothie和dwc都是正确的。
针对这个问题,bothie的回答可以概括为:这是未定义的行为。这并不意味着它一定是不可预测的,而是因不同的操作系统会有不同的处理方式。似乎像Solaris和HP-UX这样的操作系统在这种情况下从select(2)
返回,但是根据linux-kernel邮件列表中的此帖子,Linux不会。
在linux-kernel邮件列表上的讨论基本上是,这是一个未定义的(破碎的)行为,不能依靠它。在Linux的情况下,调用close(2)
关闭文件描述符相当于将其引用计数减小了。由于还有一个select(2)
调用引用它,该文件描述符将保持打开状态并等待输入,直到select(2)
返回。这基本上就是dwc的回答。您将在文件描述符上获得一个事件,然后它将被关闭。如果该文件描述符没有被重用,则尝试从中读取将导致EBADF(“Bad file descriptor”)错误。(这是MarkR在他的答案中提到的问题,尽管我认为使用适当的同步方法可以避免这个问题。)
所以非常感谢大家的帮助。
select
进行读取时,没有可预测的方法,因为调用close
的线程无法知道另一个线程是否已经被阻塞在select
中或即将被阻塞在select
中。 - David Schwartz你的问题有点令人困惑...
Select()应该在“有趣”的更改发生时返回。如果close()只是减少引用计数并且文件仍然在某个地方打开进行写入,那么没有理由让select()唤醒。
如果另一个线程对唯一打开的描述符执行了close(),那么情况会变得更加有趣,但我需要看到代码的简化版本才能确定是否真的出现了问题。
select()
(而pipe()
是一个很好的答案),而我的问题更多地涉及到close()
在select()
选定的套接字上的行为。在下面的答案中,你会看到答案是,“这取决于情况。” - Joe Shaw