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

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

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

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

然而,Linux 上的手册页,例如男人7管,不要提到读取是原子的并且男人2读明确指出,如果读取被信号中断,则读取可能返回小于请求的数量。

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

特别是,如果管道的单个写入器总是写入(例如)12 字节块,并且该管道有 2 个并发读取器读取该管道 12 字节,那么这些读取器要么恰好读取 12 字节,要么出现类似以下EAGAIN错误没有可能获得部分阅读吗?

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

答案1

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

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

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

相关内容