我有2个进程('ls'进程和'grep')。我正在使用管道在两者之间进行通信。但是grep进程无法从管道中读取。你能帮我搞清楚为什么会这样吗?
这是我的代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int pipe_fd[2];
int main()
{
pid_t p1,p2;
char *prog1_argv[4];
char *prog2_argv[2];
/* Build argument list */
prog1_argv[0] = "ls";
prog1_argv[1] = "-l";
prog1_argv[2] = "/";
prog1_argv[3] = NULL;
prog2_argv[0] = "grep";
prog2_argv[1] = "s";
prog2_argv[1] = NULL;
if (pipe(pipe_fd) < 0)
{
printf ("pipe failed");
}
p1 = fork();
if(p1 == 0)
{
printf("in child\n");
close(pipe_fd[0]);
if(dup2(pipe_fd[1],1)<0)
{
printf("dup failed:%d\n",errno);
}
close(pipe_fd[1]);
if(execvp (prog1_argv[0], prog1_argv)<0)
printf("exec failed");
}
if(p1>0)
{
printf("im in parent\n");
waitpid(p1,NULL,0);
printf("parent: child exited. Now test the pipe\n");
close(pipe_fd[1]);
if(dup2(pipe_fd[0],0)<0)
{
printf("dup failed:%d\n",errno);
}
close(pipe_fd[0]);
if(execvp (prog2_argv[0], prog2_argv)<0)
printf("exec failed");
}
}
答案 0 :(得分:1)
你覆盖你的grep的参数。尝试:
int main()
{
pid_t p1,p2;
char *prog1_argv[4];
char *prog2_argv[3];
/* Build argument list */
prog1_argv[0] = "ls";
prog1_argv[1] = "-l";
prog1_argv[2] = "/";
prog1_argv[3] = NULL;
prog2_argv[0] = "grep";
prog2_argv[1] = "s";
prog2_argv[2] = NULL;
// ...
答案 1 :(得分:1)
从根本上说,在运行ls
之前,您不应该等待grep
死亡。
ls
命令可能会生成如此多的数据,导致它们无法全部存储在管道中,因此ls
命令将阻塞,直到另一个进程从管道读取,但另一个进程在尝试从管道读取任何内容之前等待ls
完成。这是一个僵局。
此外,通过这样等待,您可以强制执行串行执行,从而避免了多核的好处。
您应该做一些小的改进。报告错误有多种方面。应在标准错误流(stderr
)上报告错误,而不是stdout
。您还应该确保在至少一些错误之后程序不会继续。
您不必测试任何exec*()
系统调用的返回值。如果函数返回,则失败。而且,您应该确保在此之后退出流程。在这个计划中,孩子继续并不重要;在许多程序中,不退出会导致混乱(例如,两个进程同时尝试读取标准输入)。
pipe_fd
不需要成为全局变量。请确保您的所有邮件以换行符结尾。您没有包含<sys/wait.h>
,因此您在waitpid()
函数的范围内没有原型工作 - 这通常是一个坏主意。您应该将编译器设置为繁琐,因此它要求每个函数在使用或定义之前都在范围内具有原型。您可以在定义中初始化参数列表:
char *prog1_argv[] = { "ls", "-l", "/", NULL };
char *prog2_argv[] = { "grep", "s", NULL };
这有一个至关重要的有益副作用,即不用{NULL}指针prog_argv2[1]
切换Matthias answer。我还删除了数组的大小;第二个的大小为2,需要为3,但是当你像这样初始化时,编译器会进行计数。
你正确做的一件事是正确的做法是确保管道文件描述符全部关闭。
这适用于我:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
pid_t p1;
int pipe_fd[2];
char *prog1_argv[] = { "ls", "-l", "/", NULL };
char *prog2_argv[] = { "grep", "s", 0 };
if (pipe(pipe_fd) < 0)
{
fprintf(stderr, "pipe failed:%d\n", errno);
exit(1);
}
p1 = fork();
if (p1 == 0)
{
printf("In child\n");
close(pipe_fd[0]);
if (dup2(pipe_fd[1], 1) < 0)
{
fprintf(stderr, "dup failed:%d\n", errno);
exit(1);
}
close(pipe_fd[1]);
execvp(prog1_argv[0], prog1_argv);
fprintf(stderr, "exec failed:%d\n", errno);
exit(1);
}
if (p1 > 0)
{
printf("In parent\n");
close(pipe_fd[1]);
if (dup2(pipe_fd[0], 0) < 0)
{
fprintf(stderr, "dup failed:%d\n", errno);
exit(1);
}
close(pipe_fd[0]);
execvp(prog2_argv[0], prog2_argv);
fprintf(stderr, "exec failed:%d\n", errno);
exit(1);
}
fprintf(stderr, "Fork failed:%d\n", errno);
return(1);
}