管道读取不大于 PIPE_BUF 原子吗?

Igo*_*nov 5 linux pipe concurrency

GNU C 库手册简要提到管道的读取和写入都是原子的

如果写入的数据大小不大于 PIPE_BUF,则读取或写入管道数据是原子的。

但是,Linux 上的手册页,如man 7 pipe,没有提到读取是原子的,并且man 2 read明确指出,如果读取被信号中断,则 read 可能返回少于请求的数量。

那么对具有以下读取长度的管道的读取调用PIPE_BUF在 Linux 上真的是原子的吗?

特别是,如果一个作家管道总是写,例如,12字节块,并有2个为12个字节读管道管并发读取,执行这些读者要么得到确切12字节读取或类似的错误EAGAIN有不可能获得部分阅读?

另外,当作者按 12 字节块写入但并发读者尝试PIPE_BUF/12一次读取最多块时,情况如何?成功的读取是否总是返回 12 字节的精确乘数,还是可以返回任意数量的字节?

Gil*_*il' 3

查看源代码,pipe_readin的实现source/fs/pipe.c在 Linux 内核中发生了很大的变化,但是通过快速阅读2.0.402.4.372.6.323.114.9中的代码,在我看来,每当有(或正在阻塞时)大小为wread的写入和大小为r的读取且r > w时,将至少返回w字节。因此,如果您有固定大小的块(大小小于)并且始终读取相同大小的数据,那么实际上保证您始终读取整个块。readPIPE_BUF

另一方面,如果你有可变大小的块,那么你就没有这样的保证。仅在写入端保证原子性:小于的写入PIPE_BUF不会被另一个写入器剪切。但在读取器方面,如果先写入 10 个字节,然后再写入 20 个字节,然后您尝试读取 15 个字节,那么您将获得完整的第一个写入和第二个写入的前 5 个字节写。该read调用不会停止读取数据,直到它必须阻塞或其输出缓冲区已满。

如果要以块的形式传输数据,请使用数据报套接字而不是管道。