在原子内容的意义上,从匿名管道原子读取
Is reading from an anonymous pipe atomic, in the sense of atomic content?
我正在Linux上编写一个具有两个线程的进程。它们使用由pipe()
调用创建的匿名管道进行通信。
一端将C结构复制到管道中:
struct EventStruct e;
[...]
ssize_t n = write(pipefd[1], &e, sizeof(e));
另一端从管道中读取:
struct EventStruct e;
ssize_t n = read(pipefd[0], &e, sizeof(e));
if(n != -1 && n != 0 && n < sizeof(e))
{
// Is a partial read possible here??
}
匿名管道可以发生部分读吗?
手册页(man 7 pipe
)规定在PIPE_BUF大小下的任何写都是原子的。但他们的意思是原子对于其他作家线程…我不关心多个作家的问题。我只有一个写线程和一个读线程。
作为旁注,我的结构是56字节长。远低于PIPE_BUF大小,在Linux上至少为4096字节。在最新的内核中,它看起来甚至更高。
否则:在读端,我是否必须处理部分读和存储它们,同时我收到一个完整的结构实例?
只要处理的是固定大小的单位,就没有问题。如果您在管道上写入一个N字节的单位,并且读取器从管道请求一个N字节的单位,那么就不会有问题。如果您不能一次性读取所有数据(例如,在读取其长度之前您不知道其大小),那么生活会变得更加棘手。但是,如图所示,您应该没问题。
也就是说,您仍然应该检测到短读取。如果你只读了一小段,却认为它是完整的,那将是一场灾难。但是,您不应该期望检测到短读取-代码覆盖将是一个问题。我只是测试n < (ssize_t)sizeof(e)
和任何检测到的是错误或EOF。注意演员阵容;否则,有符号值将被转换为无符号值,-1
将无法被正确识别。
对于规范,您需要阅读POSIX规范:
-
read()
-
write()
-
pipe()
并可能跟踪这些页面的链接。例如,对于write()
,规范说:
对管道或FIFO的写请求应以与常规文件相同的方式处理,但有以下例外:
没有与管道相关的文件偏移量,因此每个写请求都必须附加到管道的末尾。
{PIPE_BUF}字节或更少的写请求不能与在同一管道上进行写操作的其他进程的数据交叉。无论是否设置了文件状态标志的O_NONBLOCK标志,大于{PIPE_BUF}字节的写操作可能会在任意边界上与其他进程的写操作交叉。
或来自read()
的规范:
操作完成后,当
nbyte
大于0时,read()
将标记为更新文件的最后一次数据访问时间戳,并返回读取的字节数。这个数字不能大于nbyte
。如果文件中的剩余字节数小于nbyte
,如果read()请求被信号中断,或者文件是管道或FIFO或特殊文件并且立即可用的读取字节少于nbyte
,则返回的值可能小于nbyte
。例如,来自与终端相关联的文件的read()
可能返回一个键入的数据行。
所以,write()
会写原子单位;read()
将只读取原子单位,因为这是写入的内容。就像我一开始说的,不会有问题的。
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 先进先出:一个进程永远不会从管道读取
- C++命名管道客户端读取的字节不会超过 4096 字节
- 如何使客户端在将数据写入 C++ 管道之前检查服务器是否完成了从管道的读取操作
- 使用命名管道块的读取文件,尽管使用重叠
- 使用管道从 STDIN 读取分叉进程时出现问题
- 管道未正确读取数据
- read() 在 select() 阻塞之后,当从生成的进程从管道读取时
- 读取文件挂在管道读取上
- 使用两个不同的管道C 读取和写入相同的过程
- 启动子进程时的争用条件导致从管道读取挂起
- 如何在C++中读取进化邮件管道
- 为什么从管道读取时libc++getline会阻塞,而libstdc++getline不会
- 无法读取在cmd.exe管道下启动的进程的输出
- C++双向管道-在循环中尝试从子进程读取时卡住
- 父进程不读取管道表单
- 如何使用 mingw 读取管道并将其放入字符串变量中
- 正在读取管道输入
- 阻塞读取管道的调用
- Linux -子读取管道接收发送到标准输出的调试消息