c - 在 C 中,为什么我的程序在尝试管道多个命令时卡在 wait() 上?
问题描述
我正在编写一个简单的程序来在三个命令之间进行管道传输。对于每个命令,我 fork 一个子节点并在其中调用 execvp,而父节点等待 execvp 完成(注意因为我 fork 3 次,所以我调用 wait(NULL) 3 次)
我创建了两个管道,pipe_A 和 pipe_Z。流程类似于:
命令 1 将其输出写入 pipe_A,命令 2 从 pipe_A 读取输入,然后将输出写入 pipe_Z,然后命令 3 从 pipe_Z 读取输入,然后写入标准输出。
问题是程序卡在第二个等待(NULL)上。在我的代码中,它是 'printf("reached\n");' 之后的行。程序不会终止,并且在我发送中断之前一直卡住。
如果我用相同的命令“echo hello”替换所有三个命令,它不会做太多,但程序至少会结束。
我编写了一个较小的程序(相同的结构),只有两个命令(“echo hello”和“wc”),它也卡住了,就在第一次等待(NULL)。但是,我注意到,如果我在主程序的第二个命令上调用 execvp,输出会按预期打印。但是,程序也会立即终止(因为 execvp),所以这不是我想要的方式。
我怀疑我犯了一个非常明显的错误,因为缺乏对管道如何工作或 wait(NULL) 函数调用如何工作的理解。
诠释主要(){
//### COMMANDS AS STRING ARRAYS ###
char * cmds1[3] = {"echo","hello", NULL};
char * cmds2[3] = {"cat","-",NULL};
char * cmds3[3] = {"wc", NULL};
//### CREATING PIPES ###
int pipe_A[2];
int pipe_Z[2];
pipe(pipe_A);
pipe(pipe_Z);
//### FIRST FORK FOR FIRST EXECVP ###
int pid = fork();
//Child process
if(pid==0){
close(pipe_A[0]);
dup2(pipe_A[1], STDOUT_FILENO);
execvp(cmds1[0],cmds1);
exit(1);
}
//Parent process
else if(pid >0){
wait(NULL);
}
//### SECOND FORK FOR SECOND EXECVP ###
int pid2 = fork();
//Child process
if(pid2==0){
close(pipe_A[1]);
dup2(pipe_A[0],STDIN_FILENO);
close(pipe_Z[0]);
dup2(pipe_Z[1], STDOUT_FILENO);
execvp(cmds2[0],cmds2);
exit(1);
}
//Parent process
else if(pid2>0){
printf("reached\n");
wait(NULL);
}
//### THIRD FORK FOR THIRD EXECVP ###
int pid3 = fork();
//Child process
if(pid3==0){
close(pipe_Z[1]);
dup2(pipe_Z[0],STDIN_FILENO);
execvp(cmds3[0],cmds3);
exit(1);
}
//Parent process
else if(pid2 >0){
wait(NULL);
}
//### END OF PROGRAM ###
return 0;
}
预期输出为“1 1 6”,但程序不会终止。
解决方案
您没有关闭父进程中管道的写端,所以它们都没有真正关闭,所以没有一个子进程得到 EOF,所以没有一个子进程(除了echo
不读取输入)永远退出。
推荐阅读
- regex - 当dayOfWeek的值为零时,是否可以将单元格留空?
- c# - 中间件向 DI 容器或服务添加新的依赖项
- regex - 创建与另一个部分匹配的新字符串变量
- linux - 如何使用相对密码 + 字符串创建别名
- javascript - 选择选项后是否可以专注于文本区域?
- excel - 有没有办法在数据透视表中显示总计列的百分比差异?
- sql - 在 SQL 中编写嵌套查询的更好方法
- c# - EF Core - 如何检索聚合根的关联实体?
- typescript - 如何在 TypeScript 中将一个字符串拆分为两个变量?
- javascript - window.location.href 在 URL 中添加路径