我正在尝试执行一个小C程序,该程序实现了两个bash命令的管道:echo $ arithmeticoperation |BC
$ arithmeticoperation是一个字符串作为输入。
该程序可以很好地执行第一个命令,但是当我运行第二个命令时,我得到了正确的输出,但是执行BC的子进程仍然卡住了,阻止了孩子结束。
因此,在此行中,父亲的过程被阻止: waitpid(pid2,null,0(;
您认为问题可能在哪里?
对不起,如果我错误地问了这个问题,那是我的第一个问题。谢谢。
#define SYSCALL(r,c,e) if((r=c)==-1) { perror(e);exit(EXIT_FAILURE);}
int main(){
char buf[128];
int pfd[2],err;
pid_t pid1,pid2;
SYSCALL(err,pipe(pfd),"pipe");
switch (pid1=fork()) {
case -1: { perror("fork"); exit(EXIT_FAILURE);}
case 0 : {
scanf("%s",buf);
SYSCALL(err,dup2(pfd[1],1),"dup");
close(pfd[1]);
close(pfd[0]);
execl("/bin/echo","echo",buf,(char *)NULL);
return 1;
}
}
switch (pid2=fork() ){
case -1 : { perror("fork"); exit(EXIT_FAILURE);}
case 0 : {
SYSCALL(err,dup2(pfd[0],0),"dup");
close(pfd[1]);
close(pfd[0]);
// execl("/usr/bin/bc","bc",(char *)NULL);
execlp("bc","bc",(char *)NULL);
return 1;
}
}
printf("waiting . . . n");
waitpid(pid1,NULL,0);
printf("waitn");
waitpid(pid2,NULL,0);
close(pfd[1]);
close(pfd[0]);
return 0;
}
所以,如果我将" 1 1"作为输入字符串,我将获得正确的输出,但是执行BC的过程永远不会退出
正如我在评论中指出的那样,您的父进程必须在等待 bc
之前关闭管道的文件描述符问题(。
这是因为bc
的管道打开了,父母的管道打开了写作,并且内核认为父母可以将数据发送到bc
。它不会,但是可以。
管理管道时必须非常小心。您仔细避免了通常没有关闭孩子中的文件描述符的通常问题。
经验法则:如果您 dup2()
管道的一端达到标准输入或标准输出,关闭两个返回的原始文件描述符 pipe()
尽快地。特别是,您应该在使用任何一个之前关闭它们 exec*()
功能家族。
如果您用任何一个复制描述符,则该规则也适用 dup()
或者 fcntl()
使用F_DUPFD
我也需要将其扩展以涵盖父进程。
如果父过程不会通过管道与任何孩子进行通信,则必须确保其关闭管道的两端,以便其孩子可以在阅读时收到EOF指示(或获得Sigpipe信号或写错误在写(,而不是无限期地阻止。父母通常应关闭管道的至少一端 - 程序在单管的两端读写非常不寻常。