在Ubuntu 16上,我正在尝试编写一个执行管道,分叉和执行的程序:
cat
以将内容传输到第二个子进程;和grep
以选择包含转发到第三个子流程的数字的行这是我的代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <string.h>
#include <sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#define BLOCK_SIZE 4096
int main(int argc, char** argv)
{
int PID;
int pipe1[2];
int pipe2[2];
int pipe3[2];
char fileName[256];
int lengthfileName = strlen(argv[1]);
char content[BLOCK_SIZE];
char modifiedContent[BLOCK_SIZE];
int file;
if(argc < 2)
{
printf("Usage prog file\n");
exit(1);
}
if(pipe(pipe1) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if(pipe(pipe2) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if(pipe(pipe3) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) //first child
{
close(pipe1[1]);
read(pipe1[0],fileName,lengthfileName);
close(pipe1[0]);
close(pipe2[0]);
dup2(pipe2[1],1);
close(pipe2[1]);
execlp("/bin/cat","cat",fileName,NULL);
exit(0);
}
else // parent
{
close(pipe1[0]);
write(pipe1[1],argv[1],lengthfileName);
close(pipe1[1]);
int status;
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) // child 2
{
close(pipe2[1]);
//read(pipe2[0],content,BLOCK_SIZE);
//dup2(pipe2[0],0);// ***********************MARKED LINE HERE *****************************************
close(pipe2[0]);
close(pipe3[0]);
dup2(pipe3[1],1);
close(pipe3[1]);
execlp("grep","grep","[0-9]",NULL);
exit(0);
}
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) //cod fiu 2
{
close(pipe3[1]);
read(pipe3[0],modifiedContent,BLOCK_SIZE);
close(pipe3[0]);
printf("GOT FROM PIPE:%s",modifiedContent);
exit(0);
}
waitpid(PID, &status, 0);
}
return 0;
}
我的问题出在子进程2代码中,我尝试将管道用作grep
的输入。如图所示,输入来自终端;如果我取消注释标记的行然后程序挂起,我必须手动杀死它以使其停止。
我如何使用pipe2
向子进程2中的grep
提供数据有什么问题?或者是其他地方的问题?
答案 0 :(得分:0)
通过管道将文件名传输给第一个子节点有点傻,但依赖于从父节点继承其长度的子节点。如果你要继承名称的长度,那么你也可以继承整个文件名,省去第一个管道。
你可以想象首先在管道上发送(固定大小)长度值以避免继承它,但这样的方案毫无意义 - 分叉子进程不仅从父进程继承数据,你不能避免依赖于在你的程序中。特别是,子必须从父级继承打开的管道末端和管道文件描述符数组,以便单亲方法可以工作。
另请注意,您(或许)幸运地通过管道收到的文件名空终止。第一个孩子既不从管道中读取它也不明确地设置它。
但主要问题似乎是你有流浪的管道末端。在分叉任何子项之前,您在父项中创建所有三个管道。因此,在每个分支处,子项将继承所有管道末端的打开文件描述符,而父级尚未关闭。子进程应该关闭它们不使用的所有打开的管道末端,但它们只关闭其中的一些。 grep
(和cat
)等程序在看到文件末尾之前不会退出,并且当任何进程成立时,它们不会在管道上看到它写结束打开。
具体来说,父进程永远不会关闭pipe2
的写结束,实际上第三个子进程继承该开放描述符并且也不会关闭它。第一个孩子在退出时关闭该FD的副本,但在管道末端打开另外两个手柄时,该末端保持打开状态。因此,当第二个孩子从该管道获取其输入时,它永远不会看到文件结束,并且永远不会退出。让父母关闭pipe2
的两端,分叉第二个孩子并分叉第三个孩子应该解决这个问题。