我有两个使用命名管道创建的进程。 writer进程使用write()写入消息,reader进程使用read()读取消息。我注意到当writer关闭管道时read()会阻塞。是否可以让编写器进程在关闭管道之前发送EOF,以便不会阻止读取器?
答案 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
常量,因为它增加了其定义的混乱。 EOF
是getchar(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 ...