27

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

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

4

4 回答 4

23

从一些额外的调查来看,dwc 和bothie 似乎都是正确的。

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

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

所以谢谢大家的帮助。

于 2009-02-19T17:09:17.503 回答
7

我希望它的行为就像已经到达文件结尾一样,也就是说,它会返回显示为就绪的文件描述符,但随后任何读取它的尝试都会返回“错误的文件描述符”。

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

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

于 2009-02-12T21:59:52.660 回答
6

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

这另外意味着,不需要单独的线程,因为可以在线程中完成的所有工作也可以在 select 调用之前完成。如果工作需要很长时间,它可以被中断,选择被调用超时={0,0},文件描述符得到处理,然后工作被恢复。

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

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

问候, 博多

于 2009-02-13T15:40:17.400 回答
3

你在问什么有点令人困惑......

Select() 应该在“有趣”的变化时返回。如果 close() 只是减少了引用计数并且文件仍然打开以便在某处写入,那么 select() 没有理由唤醒。

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

于 2009-02-12T22:13:07.917 回答