GNU C 库手册简要提到管道的读取和写入都是原子
如果写入的数据大小不大于 PIPE_BUF,则读取或写入管道数据是原子的。
然而,Linux 上的手册页,例如男人7管,不要提到读取是原子的并且男人2读明确指出,如果读取被信号中断,则读取可能返回小于请求的数量。
那么,对读取长度小于以下的管道的读取调用PIPE_BUF
在 Linux 上真的是原子的吗?
特别是,如果管道的单个写入器总是写入(例如)12 字节块,并且该管道有 2 个并发读取器读取该管道 12 字节,那么这些读取器要么恰好读取 12 字节,要么出现类似以下EAGAIN
错误没有可能获得部分阅读吗?
PIPE_BUF/12
另外,当写入者按 12 字节块写入但并发读取器尝试一次读取最多块时,情况又如何呢?成功读取是否总是返回 12 字节的精确乘数,还是可以返回任意数量的字节?
答案1
查看源代码,pipe_read
in的实现source/fs/pipe.c
在Linux内核中发生了相当大的变化,但是从快速阅读in的代码来看2.0.40,2.4.37,2.6.32,3.11和4.9,在我看来,每当有(或正在read
阻塞时)写入大小w和尺寸的读取r和r>w那么read
至少会返回w字节。因此,如果您有固定大小的块(大小小于PIPE_BUF
)并且始终读取相同大小的数据,那么实际上保证您始终读取整个块。
另一方面,如果你有可变大小的块,那么你就没有这样的保证。仅在写入端有原子性保证:小于的写入PIPE_BUF
不会被另一个写入器剪切。但在读取器方面,如果先写入 10 个字节,然后写入 20 个字节,然后您尝试读取 15 个字节,那么您将获得完整的第一个写入和第二个写入的前 5 个字节写。该read
调用不会停止读取数据,直到它必须阻塞或其输出缓冲区已满。
如果您想以块的形式传输数据,请使用数据报套接字而不是管道。