c 在某些情况下导致程序挂起的管道
c Pipes causing program to hang in some cases
我正在尝试使用管道将 1 个命令的标准输出 link 执行到另一个命令的标准输入。例如模仿 (cmd1 | cmd2)
下面是我的代码的精简版本。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argC, char *argv[])
{
//Run first command
int fds[2];
if (pipe (fds) < 0) { //Create pipe
fprintf (stderr, "Pipe Failed\n");
}
int pid;
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 1 Failed\n");
exit (1);
}
if (pid == 0) { //First child proccess
close (fds[0]); //Close input end of pipe
dup2 (fds[1], STDOUT_FILENO); //Set stdout to output pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 1 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("ls", "ls", NULL);//Causes hang
fprintf (stderr, "Exec 1 failed\n");
} else { //First parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 1 to finish
fprintf (stderr, "Back to parent 1\n");
}
//Run second command
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 2 failed\n");
}
if (pid == 0) { //second child proccess
dup2 (fds[0], STDIN_FILENO); //Set stdin to input pipe
close (fds[0]); //Close input end of pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 2 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("wc", "wc", NULL);//Causes hang
fprintf (stderr, "Exec 2 failed\n");
} else { //second parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 2 to finish
fprintf (stderr, "Back to parent 2\n");
//Done with pipes
close (fds[0]);
close (fds[1]);
}
return 0;
}
在程序中,我尝试制作一个管道并将第一个 execs stdout 路由到第二个 stdin。尝试使用 ls | 运行 程序时 | wc 作为我的执行程序,我的程序挂在第二个执行程序上。然而,当我使用一个简单的程序“./addone”作为我的 execs 时,整个执行正确完成。
其中"addone"是小程序:
#include<stdio.h>
int main(){
int value = 0;
scanf("%d", &value);
value++;
printf("%d\n", value);
}
有人建议我的问题可能是输入管道处于打开状态,但我无法弄清楚会发生什么,并且它不能解释为什么我的程序 运行 在使用时完美无缺我的简单测试程序。
任何关于导致此挂起的原因的建议将不胜感激。
我不知道你的问题是否解决了,但是继续评论,如果你要构建一个管道,关键是要理解如果你在一个进程中写入一个管道,你必须在下一个进程中从同一管道读取,如果要继续管道,则写入第二个管道。现在您可以将过程自动化,如 link C Minishell Adding Pipelines 中所示,但出于学习目的,如果您只研究单个线性示例,可能更容易理解。
下面是使用两个文件描述符 fd1
和 fd2
实现的代码。您的 addone
进程将首先从普通的旧 stdin
读取,因此不会为读取操作文件描述符。但是,对于它的写入,它必须使用 fd1
的 write-end(因为缺少更好的词)将其输出通过管道传输到下一个 child过程。
下一个 child 进程必须从同一个 fd1
的 input-end 中读取以接收其输入,并且它必须写入output-end 另一个文件描述符 fd2
。在两个 child 退出后, parent 进程必须从哪里读取?? (最后的管道也写的是什么...?啊哈!)fd2
。所以 parent 重复 fd2
的 read-end (关闭所有其他未使用的末端)并阅读多少 addone
的最终答案添加到初始数量。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (void) {
int fd1[2], fd2[2]; /* file descriptors 1 & 2 */
int pid;
if (pipe (fd1) < 0 || pipe (fd2) < 0) { /* open both pipes */
fprintf (stderr, "pipe creation failed\n");
}
if ((pid = fork ()) == -1) {
fprintf (stderr, "fork 1 failed\n");
exit (1);
}
if (pid == 0) { /* first child */
dup2 (fd1[1], STDOUT_FILENO); /* dup write-end of 1st */
close (fd1[0]); /* close all others */
close (fd2[0]);
close (fd2[1]);
fprintf (stderr, "Exec 1 executing now\n");
execlp ("./addone", "./addone", NULL);
fprintf (stderr, "Exec 1 failed\n");
}
else {
int returnStatus;
waitpid (pid, &returnStatus, 0);
fprintf (stderr, "Back to parent 1\n");
}
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 2 failed\n");
}
if (pid == 0) { /* second child */
dup2 (fd1[0], STDIN_FILENO); /* dup read-end of 1st */
dup2 (fd2[1], STDOUT_FILENO); /* dup write-end of 2nd */
close (fd1[1]); /* close all others */
close (fd2[0]);
fprintf (stderr, "Exec 2 executing now\n");
execlp ("./addone", "./addone", NULL);
fprintf (stderr, "Exec 2 failed\n");
}
else {
int returnStatus;
waitpid (pid, &returnStatus, 0);
fprintf (stderr, "Back to parent 2\n");
}
dup2 (fd2[0], 0); /* dup read-end of 2nd */
close (fd2[1]); /* close all others */
close (fd1[0]);
close (fd1[1]);
int total;
scanf ("%d", &total);
printf ("The total was: %d\n\n", total);
close (fd2[0]);
return 0;
}
例子Use/Output
$ echo 10 | ./bin/pipeaddone
Exec 1 executing now
Back to parent 1
Exec 2 executing now
Back to parent 2
The total was: 12
仔细阅读,如果您有任何问题,请告诉我。一旦你明白了,它就有意义了。如果你暂时不用它,别担心,你会 re-learn 重新开始 :)
我正在尝试使用管道将 1 个命令的标准输出 link 执行到另一个命令的标准输入。例如模仿 (cmd1 | cmd2)
下面是我的代码的精简版本。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argC, char *argv[])
{
//Run first command
int fds[2];
if (pipe (fds) < 0) { //Create pipe
fprintf (stderr, "Pipe Failed\n");
}
int pid;
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 1 Failed\n");
exit (1);
}
if (pid == 0) { //First child proccess
close (fds[0]); //Close input end of pipe
dup2 (fds[1], STDOUT_FILENO); //Set stdout to output pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 1 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("ls", "ls", NULL);//Causes hang
fprintf (stderr, "Exec 1 failed\n");
} else { //First parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 1 to finish
fprintf (stderr, "Back to parent 1\n");
}
//Run second command
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 2 failed\n");
}
if (pid == 0) { //second child proccess
dup2 (fds[0], STDIN_FILENO); //Set stdin to input pipe
close (fds[0]); //Close input end of pipe
close (fds[1]); //Close output end of pipe
fprintf (stderr, "Exec 2 executing now\n");
execlp ("./addone", "./addone", NULL); //execute first command - Doesnt cause hang
//execlp("wc", "wc", NULL);//Causes hang
fprintf (stderr, "Exec 2 failed\n");
} else { //second parent segment
int returnStatus;
waitpid (pid, &returnStatus, 0); //Wait for child 2 to finish
fprintf (stderr, "Back to parent 2\n");
//Done with pipes
close (fds[0]);
close (fds[1]);
}
return 0;
}
在程序中,我尝试制作一个管道并将第一个 execs stdout 路由到第二个 stdin。尝试使用 ls | 运行 程序时 | wc 作为我的执行程序,我的程序挂在第二个执行程序上。然而,当我使用一个简单的程序“./addone”作为我的 execs 时,整个执行正确完成。
其中"addone"是小程序:
#include<stdio.h>
int main(){
int value = 0;
scanf("%d", &value);
value++;
printf("%d\n", value);
}
有人建议我的问题可能是输入管道处于打开状态,但我无法弄清楚会发生什么,并且它不能解释为什么我的程序 运行 在使用时完美无缺我的简单测试程序。
任何关于导致此挂起的原因的建议将不胜感激。
我不知道你的问题是否解决了,但是继续评论,如果你要构建一个管道,关键是要理解如果你在一个进程中写入一个管道,你必须在下一个进程中从同一管道读取,如果要继续管道,则写入第二个管道。现在您可以将过程自动化,如 link C Minishell Adding Pipelines 中所示,但出于学习目的,如果您只研究单个线性示例,可能更容易理解。
下面是使用两个文件描述符 fd1
和 fd2
实现的代码。您的 addone
进程将首先从普通的旧 stdin
读取,因此不会为读取操作文件描述符。但是,对于它的写入,它必须使用 fd1
的 write-end(因为缺少更好的词)将其输出通过管道传输到下一个 child过程。
下一个 child 进程必须从同一个 fd1
的 input-end 中读取以接收其输入,并且它必须写入output-end 另一个文件描述符 fd2
。在两个 child 退出后, parent 进程必须从哪里读取?? (最后的管道也写的是什么...?啊哈!)fd2
。所以 parent 重复 fd2
的 read-end (关闭所有其他未使用的末端)并阅读多少 addone
的最终答案添加到初始数量。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (void) {
int fd1[2], fd2[2]; /* file descriptors 1 & 2 */
int pid;
if (pipe (fd1) < 0 || pipe (fd2) < 0) { /* open both pipes */
fprintf (stderr, "pipe creation failed\n");
}
if ((pid = fork ()) == -1) {
fprintf (stderr, "fork 1 failed\n");
exit (1);
}
if (pid == 0) { /* first child */
dup2 (fd1[1], STDOUT_FILENO); /* dup write-end of 1st */
close (fd1[0]); /* close all others */
close (fd2[0]);
close (fd2[1]);
fprintf (stderr, "Exec 1 executing now\n");
execlp ("./addone", "./addone", NULL);
fprintf (stderr, "Exec 1 failed\n");
}
else {
int returnStatus;
waitpid (pid, &returnStatus, 0);
fprintf (stderr, "Back to parent 1\n");
}
if ((pid = fork ()) == -1) {
fprintf (stderr, "Fork 2 failed\n");
}
if (pid == 0) { /* second child */
dup2 (fd1[0], STDIN_FILENO); /* dup read-end of 1st */
dup2 (fd2[1], STDOUT_FILENO); /* dup write-end of 2nd */
close (fd1[1]); /* close all others */
close (fd2[0]);
fprintf (stderr, "Exec 2 executing now\n");
execlp ("./addone", "./addone", NULL);
fprintf (stderr, "Exec 2 failed\n");
}
else {
int returnStatus;
waitpid (pid, &returnStatus, 0);
fprintf (stderr, "Back to parent 2\n");
}
dup2 (fd2[0], 0); /* dup read-end of 2nd */
close (fd2[1]); /* close all others */
close (fd1[0]);
close (fd1[1]);
int total;
scanf ("%d", &total);
printf ("The total was: %d\n\n", total);
close (fd2[0]);
return 0;
}
例子Use/Output
$ echo 10 | ./bin/pipeaddone
Exec 1 executing now
Back to parent 1
Exec 2 executing now
Back to parent 2
The total was: 12
仔细阅读,如果您有任何问题,请告诉我。一旦你明白了,它就有意义了。如果你暂时不用它,别担心,你会 re-learn 重新开始 :)