我在读Linux 编程接口。
从63.2.3 文件描述符什么时候准备好?, 它说:
正确使用
select()
文件描述符poll()
需要了解文件描述符指示就绪的条件。 SUSv3 表示O_NONBLOCK
,如果对 I/O 函数的调用不会阻塞,则 文件描述符(带有清除)被认为已准备好,无论该函数是否实际传输数据。重点是斜体:select()
告诉poll()
我们一个I/O操作是否不会阻塞,而不是它是否会成功传输数据。有鉴于此,让我们考虑一下这些系统调用如何针对不同类型的文件描述符进行操作。我们在包含两列的表格中显示此信息:
- 该
select()
列指示文件描述符是否被标记为可读 (r)、可写 (w) 或具有异常条件 (x)。....
管道和 FIFO
表 63-4 总结了管道或 FIFO 读端的详细信息。该
Data in pipe?
列指示管道是否至少有 1 个字节的数据可供读取。在此表中,我们假设 在的字段POLLIN
中指定了。events
poll()
....
表 63-4:管道或 FIFO 读端的
select()
指示poll()
Condition or event | select() | poll() Data in pipe? | Write end open? | no | no | r | POLLHUP yes | yes | r | POLLIN yes | no | r | POLLIN | POLLHUP
表 63-5:管道或 FIFO 写入结束的指示
select()
( 在此表中,我们假设在 的事件字段中指定。)poll()
POLLOUT
poll()
Condition or event | select() | poll() Space for PIPE_BUF bytes? | Read end open? | no | no | w | POLLERR yes | yes | w | POLLOUT yes | no | w | POLLOUT | POLLERR
我不明白两个表的第一行条件。
管道中没有数据,写入端关闭,select()
是否表明该文件描述符为可读文件描述符?为什么?select()
在管道中有数据之前不应该阻塞吗?
没有字节空间PIPE_BUF
,读端关闭,select()
是否表明它是可写文件描述符?
答案1
假设您打开管道(读取端),没有数据但写端也是开放的。如果您read()
在这种情况下执行 a,您将被阻止 - 并且select()
不会将 FD 报告为可读。我想我们在这一点上是一致的,对吧?
现在假设你正处于这种阻塞之中read()
,而作者close()
则处于管道的一端。会发生什么?您的read()
回报,结果为0
.如果你打电话,几乎同样的事情会发生read()
后作家close
s.只有你不会阻止 -read
会立即返回,也有0
结果。因此,根据您引用的来源中的推理,您的 FD 是“可读的” - 或者也许更好地说“不可阻止”,这就是select
实际报告的内容。
如果您尝试编写一个小示例,您会发现这个定义实际上比您似乎建议的更“直观”的定义更干净、更优雅的代码。
答案2
如果之前从未打开过写入端(即在 Linux 上),系统调用 select(2)(和 poll(2))将在 FIFO 的读取端阻塞。
相反,如果写入端已关闭,则两者都不会阻塞 PIPE 的读取端。
不同之处在于 FIFO 是在两端都关闭的情况下创建的,而管道是在两端都打开的情况下创建的。 select(2)(和 poll(2))重现了 Unix 早期发生的情况,当时只存在阻塞同步(在引入 select(2) 和 BSD 套接字 API 之前——通常是在引入非阻塞之前) Unix)。
由于 FIFO 的读取端只有在写入端也打开后才能成功打开,因此 read(2) 始终会查找具有打开的写入端的 FIFO。因此,如果之前从未打开过写入端,则 select(2) 和 poll(2) 都在 FIFO 的读取端上阻塞(仅当读取端已使用 O_NONBLOCK 打开时才可能)才符合逻辑。
是的,如果写入端已打开(并由最后一个写入器关闭)至少一次,则表 63-4 中关于 FIFO 的 LPI 才是正确的。