如何在关闭后避免阻止来自命名管道的read()

时间:2015-10-22 14:59:14

标签: c linux named-pipes

我有两个使用命名管道创建的进程。 writer进程使用write()写入消息,reader进程使用read()读取消息。我注意到当writer关闭管道时read()会阻塞。是否可以让编写器进程在关闭管道之前发送EOF,以便不会阻止读取器?

2 个答案:

答案 0 :(得分:2)

不...发送EOF是不可能的,因为EOF没有映射到通过频道发送的内容。 EOF条件(是的,这是一个条件,不是你通过频道收到或发送的东西)意味着没有更多的数据到read(2)并且通过使read(2)返回0来获得一个过程字符读。您在EOF条件下执行的读取次数很多,它们将返回值0,这意味着没有更多数据。

顺便说一下,当没有数据可用时,管道会阻止读者,但是,由于编写者仍在那里发送更多数据,因此没有EOF条件。通过设计,管道在没有可用数据时阻止读取器(但是编写器仍然打开管道)并且当没有更多空间将数据放入fifo时阻塞编写器(当有读取器打开fifo时会发生这种情况,但没有他们正在阅读)正如你所看到的那样,它不是一个错误。

如果您想要read(2)非阻止,并且在没有可用数据的情况下获取0,您可以open(2)O_NONBLOCK标记(或稍后执行,{ fcntl(2)系统调用),这将使read(2)立即返回可用数据(即使没有可用的数据),但它有一个缺点:那么你无法区分没有可用数据的fifo(它尚未写出来自实际的EOF(作者已经关闭了它),因为两者都会以0作为结果返回。

顺便说一下,在讨论文件结尾条件时,我不喜欢使用EOF常量,因为它增加了其定义的混乱。 EOFgetchar(3)文件末尾条件下返回的值,但它不是char(如果您检查getchar(3)的定义你会发现它被定义为int而不是char,这是为了将EOF条件添加到整个可能的char值范围内 - 所以,有257个从getchar(3)0-256为数据返回的可能值,以及文件结束条件EOF

如果您希望作家发信号文件结尾,则必须close(2) fifo并重新打开它。

答案 1 :(得分:1)

当编写器关闭管道时,即使 被阻止(例如它将被唤醒),阅读器也不会阻塞。读取调用将返回0,表示管道上的EOF。读者应该这样做:

rlen = read(pipefd,buf,sizeof(buf));
if (rlen <= 0)
    break;

您是否在查看退货代码?

在编写器中,如果读者过早地关闭了管道(例如它已中止),则编写器将从-1写入返回并且将errno设置为EPIPE。它也可以获得SIGPIPE。

见man 7 pipe ...