使用EOF在未命名管道上发信号 [英] using EOF for signaling on unnamed pipes

查看:97
本文介绍了使用EOF在未命名管道上发信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个测试程序,该程序使用在Linux系统上使用用pipe()创建的未命名管道在用fork()创建的父进程和子进程之间进行通信.

I have a test program that uses unnamed pipes created with pipe() to communicate between parent and child processes created with fork() on a Linux system.

通常,当发送过程关闭管道的写入fd时,接收过程从read()返回值为0的值,表示EOF.

Normally, when the sending process closes the write fd of the pipe, the receiving process returns from read() with a value of 0, indicating EOF.

但是,如果我在管道中填充了大量数据(似乎在接收方开始读取之前为100K字节0),则接收方将在读取管道中的所有数据后阻塞-即使发送方已将其关闭.

However, it seems that if I stuff the pipe with a fairly large amount of data (maybe 100K bytes0 before the receiver starts reading, the receiver blocks after reading all the data in the pipe - even though the sender has closed it.

我已经验证了发送过程已使用lsof关闭了管道,而且很显然接收方已被阻塞.

I have verified that the sending process has closed the pipe with lsof, and it seems pretty clear that the receiver is blocked.

哪个问题导致了:封闭管道的一端是否是一种可靠的方式,可以让接收者知道没有更多的数据了?

Which leads to the question: is closing one end of the pipe a reliable way to let the receiver know that there is no more data?

如果是这样,并且没有任何条件可以导致在封闭的空FIFO上阻塞read(),则我的代码有问题.如果没有,那意味着我需要找到一种替代方法来用信号通知数据流的结束.

If it is, and there are no conditions that can lead to a read() blocking on an empty, closed FIFO, there's something wrong with my code. If not, it means I need to find an alternate method of signalling the end of the data stream.

解决方案

我非常确定最初的假设是正确的,关闭管道会导致读者侧的EOF,这个问题只是在黑暗中打了个草稿-认为也许我忽略了一些微妙的管道行为.几乎您在管道上看到的每个示例都是一个发送一些字节并退出的玩具.当您不再执行原子操作时,事情通常会有所不同.

I was pretty sure that the original assumption was correct, that closing a pipe causes an EOF at the reader side, this question was just a shot in the dark - thinking maybe there was some subtle pipe behavior I was overlooking. Nearly every example you ever see with pipes is a toy that sends a few bytes and exits. Things often work differently when you are no longer doing atomic operations.

无论如何,我都试图简化代码以消除问题,并成功地找到了我的问题.用伪代码,我最终做了这样的事情:

In any case, I tried to simplify my code to flush out the problem and was successful in finding my problem. In pseudocode, I ended up doing something like this:

create pipe1
if ( !fork() ) {
    close pipe1 write fd
   do some stuff reading pipe1 until EOF
}
create pipe2
if ( !fork() )  {
   close pipe2 write fd
   do some stuff reading pipe2 until EOF
}
close pipe1 read fd
close pipe2 read fd
write data to pipe1
get completion response from child 1
close pipe1 write fd
write data to pipe2
get completion response from child 2
close pipe2 write fd
wait for children to exit

子进程读取管道1处于挂起状态,但仅在管道中的数据量变得很大时才挂起.即使我已经关闭了child1正在读取的管道,这种情况仍在发生.

The child process reading pipe1 was hanging, but only when the amount of data in the pipe became substantial. This was occurring even though I had closed the pipe that child1 was reading.

查看源代码可以发现问题所在.当我派生第二个子进程时,它获取了自己的pipe1文件描述符副本,该副本保持打开状态.即使应该只将一个进程写入管道,但在第二个进程中将其打开也无法使其进入EOF状态.

A look at the source shows the problem. When I forked the second child process, it grabbed its own copy of the pipe1 file descriptors, which were left open. Even though only one process should be writing to the pipe, having it open in the second process kept it from going into an EOF state.

使用小数据集不会出现此问题,因为child2正在迅速完成业务并退出.但是,对于更大的数据集,child2并没有很快返回,而我最终陷入了僵局.

The problem didn't show up with small data sets, because child2 was finishing its business quickly, and exiting. But with larger data sets, child2 wasn't returning quickly, and I ended up with a deadlock.

推荐答案

当编写者关闭写端时,read应该返回EOF.

read should return EOF when the writers have closed the write end.

由于先做管道,然后再进行分叉,所以两个进程都将打开写fd.可能是在读取器过程中,您忘记了关闭管道的写入部分.

Since you do a pipe and then a fork, both processes will have the write fd open. It could be that in the reader process you have forgotten to close the write portion of the pipe.

注意:自从我在Unix上编程以来已经有很长时间了.因此可能不准确.

Caveat: It has been a long time since I programmed on Unix. So it might be inaccurate.

以下是以下代码: http://www .cs.uml.edu/〜fredm/courses/91.308/files/pipes.html .查看下面的关闭未使用的"注释.

Here is some code from: http://www.cs.uml.edu/~fredm/courses/91.308/files/pipes.html. Look at the "close unused" comments below.

#include <stdio.h>

/* The index of the "read" end of the pipe */
#define READ 0

/* The index of the "write" end of the pipe */
#define WRITE 1

char *phrase = "Stuff this in your pipe and smoke it";

main () {
  int fd[2], bytesRead;

  char message [100]; /* Parent process message buffer */

  pipe ( fd ); /*Create an unnamed pipe*/

  if ( fork ( ) == 0 ) {
    /* Child Writer */
    close (fd[READ]); /* Close unused end*/
    write (fd[WRITE], phrase, strlen ( phrase) +1); /* include NULL*/
    close (fd[WRITE]); /* Close used end*/
    printf("Child:  Wrote '%s' to pipe!\n", phrase);

  } else {

    /* Parent Reader */
    close (fd[WRITE]); /* Close unused end*/ 
    bytesRead = read ( fd[READ], message, 100);
    printf ( "Parent: Read %d bytes from pipe: %s\n", bytesRead, message);
    close ( fd[READ]); /* Close used end */
  } 
}

这篇关于使用EOF在未命名管道上发信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆