Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 使用EOF在未命名管道上发送信号_Linux_Ipc_Pipe - Fatal编程技术网

Linux 使用EOF在未命名管道上发送信号

Linux 使用EOF在未命名管道上发送信号,linux,ipc,pipe,Linux,Ipc,Pipe,我有一个测试程序,它使用用pipe()创建的未命名管道在Linux系统上用fork()创建的父进程和子进程之间进行通信 通常,当发送进程关闭管道的write fd时,接收进程从read()返回值0,表示EOF 但是,如果我在管道中塞满了相当多的数据(可能在接收器开始读取之前塞满了100K字节),那么接收器在读取管道中的所有数据后就会阻塞,即使发送方已经关闭了它 我已经验证了发送进程已经用lsof关闭了管道,而且很明显接收器被阻塞了 这就引出了一个问题:关闭管道的一端是否是让接收器知道没有更多数据

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

通常,当发送进程关闭管道的write fd时,接收进程从read()返回值0,表示EOF

但是,如果我在管道中塞满了相当多的数据(可能在接收器开始读取之前塞满了100K字节),那么接收器在读取管道中的所有数据后就会阻塞,即使发送方已经关闭了它

我已经验证了发送进程已经用lsof关闭了管道,而且很明显接收器被阻塞了

这就引出了一个问题:关闭管道的一端是否是让接收器知道没有更多数据的可靠方法

如果是,并且没有任何条件会导致在一个空的、关闭的FIFO上出现read()阻塞,则说明我的代码有问题。如果不是,则意味着我需要找到另一种发送数据流结束信号的方法

分辨率

我非常确信最初的假设是正确的,即关闭管道会导致读者端的EOF,这个问题只是一个暗中猜测——我想可能有一些微妙的管道行为我忽略了。几乎你所看到的每个管道示例都是一个发送数个字节和出口的玩具。事情往往会不同当你不再做原子操作时

在任何情况下,我都试图简化我的代码以解决问题,并成功地找到了我的问题。在伪代码中,我最终做了如下操作:

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正在读取的管道,这种情况也会发生

查看源代码可以看出问题所在。当我分叉第二个子进程时,它抓取了自己的pipe1文件描述符副本,该副本保持打开状态。即使只有一个进程应该写入管道,但在第二个进程中打开它可以防止它进入EOF状态


小数据集没有出现问题,因为child2正在快速完成其业务并退出。但对于较大的数据集,child2没有快速返回,结果导致死锁。

当写入程序关闭写入端时,read应该返回EOF

由于您先执行管道,然后执行fork,这两个进程都将打开write fd。可能是在读卡器进程中,您忘记关闭管道的write部分

警告:我已经很久没有在Unix上编程了。所以它可能不准确

以下是来自的一些代码:。请查看下面的“关闭未使用的”注释

#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 */
  } 
}
#包括
/*管道“读取”端的索引*/
#定义读取0
/*管道“写入”端的索引*/
#定义写入1
char*phrase=“把它塞进你的烟斗里,然后抽出来”;
主要(){
int-fd[2],字节读取;
字符消息[100];/*父进程消息缓冲区*/
管道(fd);/*创建未命名管道*/
if(fork()==0){
/*儿童作家*/
关闭(fd[读取];/*关闭未使用的端*/
write(fd[write],短语,strlen(短语)+1);/*包括NULL*/
关闭(fd[WRITE]);/*关闭已用端*/
printf(“子级:将“%s”写入管道!\n”,短语);
}否则{
/*父读取器*/
关闭(fd[WRITE]);/*关闭未使用的端*/
bytesRead=read(fd[read],消息,100);
printf(“父:从管道读取%d字节:%s\n”,字节读取,消息);
关闭(fd[读取]);/*关闭已用端*/
} 
}

这是完全正确的。一旦所有引用管道写入端的文件描述符都关闭,
read()
将不会阻塞并返回0。很可能在某些进程中,写入端的另一个文件描述符挂起(可能是在接收进程中,或者可能是另一个子进程在
fork()之后得到了它的副本。
)。不,肯定不是第一个问题-在fork之后,我有相同的close()语句显示在此代码的每个规范实例中。当然,当我的代码仅限于像这样的短消息时,它可以正常工作。@马克:也许显示代码会有所帮助。我猜如果管道关闭,您可能不关心已经存在的数据?在这种情况下,您可能有两个管道,一个命令一个nd one data。让编写器通过命令管道发送CLOSE命令。您可以使用select调用对两个fd上的数据进行非阻塞测试。正如经常发生的那样,简化代码以尝试演示问题导致了我的错误。我的错误不太微妙,但第一次肯定就过去了。我要补充这件事马上就解决了我的问题。