管道问题:第一个 child 向管道写入过多内容
Pipe issue: first child writes too much in to pipe
我正在尝试在 C
中编写一个程序,它创建 2 个 child 进程,每个进程执行一个 execvp
。
我的问题是第一个 child 向另一个 child 读取的管道写入了太多输入。
int main(int argc, char* argv[]){
//unnamed pipe
int pipeFd[2], statusFirst,statusSecond;
pid_t childPidOne,childPidTwo;
if(pipe(pipeFd) < 0){
perror("Pipe error:\n");
exit(EXIT_FAILURE);
}
switch(childPidOne = fork()){
case -1:
perror("First Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("First child\n");
close(pipeFd[1]);
if( (execvp(argv[1], &argv[1])) < 0){
perror("First execvp error:\n");
}
printf("End First cild\n");
exit(0);
default:
//Do nothing
break;
}
switch(childPidTwo = fork()){
case -1:
perror("Second Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("Second cild\n");
close(pipeFd[0]);
if( (execvp(argv[3], &argv[3])) < 0){
perror("Second execvp error:\n");
}
printf("End Second cild\n");
exit(0);
default:
//Do nothing
break;
}
close(pipeFd[0]);
close(pipeFd[1]);
if( (waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0 ){
perror("First waitpid error:\n");
}else{
if (WIFEXITED(statusFirst)) {
printf("First exited, status=%d\n", WEXITSTATUS(statusFirst));
} else if (WIFSIGNALED(statusFirst)) {
printf("First killed by signal %d\n", WTERMSIG(statusFirst));
} else if (WIFSTOPPED(statusFirst)) {
printf("First stopped by signal %d\n", WSTOPSIG(statusFirst));
} else if (WIFCONTINUED(statusFirst)) {
printf("First continued\n");
}
}
if( (waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0 ){
perror("Second waitpid error:\n");
}
if (WIFEXITED(statusSecond)) {
printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond));
} else if (WIFSIGNALED(statusSecond)) {
printf("Second killed by signal %d\n", WTERMSIG(statusSecond));
} else if (WIFSTOPPED(statusSecond)) {
printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond));
} else if (WIFCONTINUED(statusSecond)) {
printf("Second continued\n");
}
exit(0);
return 0;
}
也许我对 pipe + fork + execvp 的工作方式理解有误所以让我告诉你我在我的代码中做了什么:
- 我创建了一个未命名的管道 - 两个 child 使用相同的管道
- 我将通过分叉创建两个 child
- 因为我这样执行我的程序:
./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]
或者只是给你一个例子:./pipeline echo Hello | wc -m
我关闭了管道的阅读站点
- 然后调用
execvp(argv[1], &argv[1])
这就是错误发生的地方(我猜):
在第二个 child 完成之前,我永远不会关闭写作方面,因为 execvp
永远不会 return 如果它成功了。
而且我知道 execvp
不会关闭打开的文件描述符(它可以通过在 fcntl
中使用标志来关闭,如 What does the FD_CLOEXEC flag do? 中所述)。
例子
我举个例子。
echo Hello | wc -m
输出结果
6
因为系统调用wc
(字数统计)计算给定String
中的字符数(-m
)
这是正确的,因为 hello = 5 + 1(我猜是 \n
或 [=26=]
),这就是 6.
现在,运行我的程序给出了结果
56
或获取更多信息
echo hello | wc
产出
1 (line) 1 (word) 6 (characters)
和./pipeline echo hello | wc
产出
3 (lines) 9 (word) 56 (characters)
我找了好几天也没弄明白
有什么想法吗?
非常感谢!
自己解决了。
忘记使用 dup2
。
只要在close
命令后输入dup2
命令就可以了。
我正在尝试在 C
中编写一个程序,它创建 2 个 child 进程,每个进程执行一个 execvp
。
我的问题是第一个 child 向另一个 child 读取的管道写入了太多输入。
int main(int argc, char* argv[]){
//unnamed pipe
int pipeFd[2], statusFirst,statusSecond;
pid_t childPidOne,childPidTwo;
if(pipe(pipeFd) < 0){
perror("Pipe error:\n");
exit(EXIT_FAILURE);
}
switch(childPidOne = fork()){
case -1:
perror("First Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("First child\n");
close(pipeFd[1]);
if( (execvp(argv[1], &argv[1])) < 0){
perror("First execvp error:\n");
}
printf("End First cild\n");
exit(0);
default:
//Do nothing
break;
}
switch(childPidTwo = fork()){
case -1:
perror("Second Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("Second cild\n");
close(pipeFd[0]);
if( (execvp(argv[3], &argv[3])) < 0){
perror("Second execvp error:\n");
}
printf("End Second cild\n");
exit(0);
default:
//Do nothing
break;
}
close(pipeFd[0]);
close(pipeFd[1]);
if( (waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0 ){
perror("First waitpid error:\n");
}else{
if (WIFEXITED(statusFirst)) {
printf("First exited, status=%d\n", WEXITSTATUS(statusFirst));
} else if (WIFSIGNALED(statusFirst)) {
printf("First killed by signal %d\n", WTERMSIG(statusFirst));
} else if (WIFSTOPPED(statusFirst)) {
printf("First stopped by signal %d\n", WSTOPSIG(statusFirst));
} else if (WIFCONTINUED(statusFirst)) {
printf("First continued\n");
}
}
if( (waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0 ){
perror("Second waitpid error:\n");
}
if (WIFEXITED(statusSecond)) {
printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond));
} else if (WIFSIGNALED(statusSecond)) {
printf("Second killed by signal %d\n", WTERMSIG(statusSecond));
} else if (WIFSTOPPED(statusSecond)) {
printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond));
} else if (WIFCONTINUED(statusSecond)) {
printf("Second continued\n");
}
exit(0);
return 0;
}
也许我对 pipe + fork + execvp 的工作方式理解有误所以让我告诉你我在我的代码中做了什么:
- 我创建了一个未命名的管道 - 两个 child 使用相同的管道
- 我将通过分叉创建两个 child
- 因为我这样执行我的程序:
./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]
或者只是给你一个例子:./pipeline echo Hello | wc -m
我关闭了管道的阅读站点 - 然后调用
execvp(argv[1], &argv[1])
这就是错误发生的地方(我猜):
在第二个 child 完成之前,我永远不会关闭写作方面,因为 execvp
永远不会 return 如果它成功了。
而且我知道 execvp
不会关闭打开的文件描述符(它可以通过在 fcntl
中使用标志来关闭,如 What does the FD_CLOEXEC flag do? 中所述)。
例子
我举个例子。
echo Hello | wc -m
输出结果
6
因为系统调用wc
(字数统计)计算给定String
-m
)
这是正确的,因为 hello = 5 + 1(我猜是 \n
或 [=26=]
),这就是 6.
现在,运行我的程序给出了结果
56
或获取更多信息
echo hello | wc
产出
1 (line) 1 (word) 6 (characters)
和./pipeline echo hello | wc
产出
3 (lines) 9 (word) 56 (characters)
我找了好几天也没弄明白
有什么想法吗?
非常感谢!
自己解决了。
忘记使用 dup2
。
只要在close
命令后输入dup2
命令就可以了。