从原子内容的意义上读取匿名管道原子?

时间:2015-09-05 21:27:31

标签: c++ c linux multithreading posix

我正在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字节。看起来它在最近的内核上更高。

否则:在阅读结束时,我是否必须处理部分读取并存储它们同时收到完整的结构实例?

1 个答案:

答案 0 :(得分:6)

只要您处理固定大小的单位,就不会有问题。如果你在管道上写一个N字节的单位,并且阅读器从管道请求一个N字节的单位,那么就没有问题。如果你不能一下子读取所有数据(例如,在你阅读了它的长度之后你就不知道它的大小),那么生活变得更加棘手。但是,如图所示,你应该没事。

那就是说,你仍然应该检测短读。如果你得到一个简短的阅读但是假设它是全长的话,那就是一场灾难。但是,您不应期望检测到短读取 - 代码覆盖率将是一个问题。我只是测试n < (ssize_t)sizeof(e),检测到的任何内容都是错误或EOF。注意演员表;否则,已签名的值将转换为未签名,并且-1无法正确发现。

对于规范,您需要阅读以下的POSIX规范:

可能跟踪这些页面的链接。例如,对于write(),规范说:

  

对管道或FIFO的写入请求应以与常规文件相同的方式处理,但以下情况除外:

     
      
  • 没有与管道关联的文件偏移量,因此每个写入请求都应附加到管道的末尾。

  •   
  • {PIPE_BUF}字节或更少字节的写请求不得与来自在同一管道上写入的其他进程的数据交错。无论是否设置了文件状态标志的O_NONBLOCK标志,大于{PIPE_BUF}字节的写入都可以在任意边界上交错数据,并且可以通过其他进程进行写入。

  •   

或者来自read()

的规范
  

成功完成后,nbyte大于0,read()应标记更新文件的最后一个数据访问时间戳,并返回读取的字节数。此数字不得大于nbyte。如果文件中剩余的字节数小于nbyte,如果read()请求被信号中断,或者文件是管道或管道,则返回的值可能小于nbyte FIFO或特殊文件,并且可以立即读取少于nbyte个字节。例如,与终端关联的文件中的read()可能会返回一个类型化的数据行。

所以,write()将写出原子单位; read()只会阅读原子单位,因为这是写的。这不是一个问题,这就是我在开始时所说的。