当前位置:嗨网首页>书籍在线阅读

11-管道和FIFO中read()和write()的语义

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

44.10 管道和FIFO中read()和write()的语义

表44-2对管道和FIFO上的read()操作进行了总结,包括O_NONBLOC标记的作用。

表44-2:从一个包含p字节的管道或FIFO中读取n字节的语义

| 是否启用 O_NONBLOCK | 管道或FIFO中可用的数据字节(p) | | :----- | :----- | :----- | :----- | | p = 0,写入端打开 | p = 0,写入端关闭 | p < n | p >= n | | 否 | 阻塞 | 返回0(EOF) | 读取p字节 | 读取n字节 | | 是 | 失败(EAGAIN) | 返回0(EOF) | 读取p字节 | 读取n字节 |

只有当没有数据并且写入端没有被打开时阻塞和非阻塞读取之间才存在差别。在这种情况下,普通的read()会被阻塞,而非阻塞read()会失败并返回EAGAIN错误。

当O_NONBLOCK标记与PIPE_BUF限制共同起作用时O_NONBLOCK标记对象管道或FIFO写入数据的影响会变得复杂。表44-3对write()的行为进行了总结。

表44-3:向一个管道或FIFO写入n字节的语义

| 是否启用O_NONBLOCK | 读取端打开 | 读取端关闭 | | :----- | :----- | :----- | :----- | :----- | | n <= PIPE_BUF | n > PIPE_BUF | | 否 | 原子地写入n字节;可能阻塞,直到足够的数据被读取以便继续执行write() | 写入n字节;可能阻塞,直到足够的数据被读取以便结束write();数据可能会与其他进程写入的数据发生交叉 | SIGPIPE + EPIPE | | 是 | 如果空间足以立即写入n字节,那么write()会原子地成功;否则就失败(EAGAIN) | 如果空间足以写入一些字节,那么写入的字节数在1到n之间(可能会与其他进程写入的数据发生交叉);否则write()会失败(EAGAIN) |

当数据无法立即被传输时O_NONBLOCK标记会导致在一个管道或FIFO上的write()失败(错误是EAGAIN)。这意味着当写入了PIPE_BUF字节之后,如果在管道或FIFO中没有足够的空间了,那么write()会失败,因为内核无法立即完成这个操作并且无法执行部分写入,否则就会破坏不超过PIPE_BUF字节的写入操作的原子性的要求。

当一次写入的数据量超过PIPE_BUF字节时,该写入操作无需是原子的。因此,write()会尽可能多地传输字节(部分写)以充满管道或FIFO。在这种情况下,从write()返回的值是实际传输的字节数,并且调用者随后必须要进行重试以写入剩余的字节。但如果管道或FIFO已经满了,从而导致哪怕连一个字节都无法传输了,那么write()会失败并返回EAGAIN错误。