我已经实现了一个简单的程序,它使用简单的管道和execvp调用模拟$ls -l | wc -c
命令执行。
现在重定向stdin和stdout后,执行程序时,shell提示符消失,等待按下回车键。
任何解决此问题的方法。 Plz批评我的代码也是..
谢谢
/* Create pipe */
ret_val=pipe(pipe_fd);
/*Error check */
if(ERROR==ret_val)
{
perror("Pipe creation error \n");
_exit(FAILURE);
}
/*Fork First Child */
pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
{
/* First sub process */
/*printf("First sub process is %d \n",getpid());*/
/* redirect stdout to pipe's write end for sub process one*/
dup2(pipe_fd[1],1);
/*close pipe read end */
close(pipe_fd[0]);
execvp(cmd_one_tokens[0],cmd_one_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
//exit(10);
}
else /*main process block */
{
/*printf(" Main process is %d \n",getpid());*/
/*Wait for first sub process to finish */
//wait(&status);
/*printf("Exit status of first child is %d \n ", WEXITSTATUS(status) );*/
/*Fork second subprocess */
pid_two = fork();
if( 0 == pid_two ) /*second child process block */
{
/* redirect stdin to pipe's read end for sub process two */
dup2(pipe_fd[0],0);
// close(0); /* close normal stdin */
// dup(pipe_fd[0]); /* make stdib same as pfds[0] */
/*close pipe write end */
close(pipe_fd[1]);
/* Second sub process */
/*printf("Second sub process is %d \n",getpid()); */
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
}
else /*main process block */
{
/* printf(" Main process is %d \n",getpid()); */
status=-1; /*reset status */
/*Waiting for the second sub process to finish in No hang fashion */
waitpid ( -1 , &status ,WNOHANG);
/*printf("Exit status of second child is %d \n ", WEXITSTATUS(status) ); */
}
}
答案 0 :(得分:2)
在分叉后,您必须在主进程中关闭管道文件描述符。在关闭它们之前,子进程(wc
)将等待主进程仍然打开的管道上的输入。您必须非常小心地关闭管道的所有不需要的端部。
答案 1 :(得分:1)
您的代码不符合您的描述:
你创建一个管道,分叉一个新进程,将它的stdout重定向到管道并让它执行一些程序(到目前为止一直这么好),然后在父进程中等待你的孩子完成,然后才分叉第二个进程,将它的stdin重定向到另一端的管道,并让它执行另一个程序。
这不是“ls | wc”的作用 - 在shell中它们同时运行。删除第一个wait()。
答案 2 :(得分:1)
pid_one = fork() ; if( 0 == pid_one ) /*child process block */
您没有检查fork(2)
错误返回,这是非常现实的可能性。 (用户可能会遇到他们的RLIMIT_NPROC
限制,kernel.threads-max
,内存不足以保存任务结构等。)
fork(2)
更惯用的使用方式如下:
if(-1 == (pid = fork()) {
perror("fork");
exit(1); /* or return -1 or similar */
} else if (0 == pid) {
/* executing as child */
} else {
/* parent, pid is child */
}
execvp(cmd_two_tokens[0] , cmd_two_tokens); /* if execvp returns then if must have failed */ printf("Unknown Command \n ");
请注意,execvp(3)
失败的原因有很多 的原因;简单地打印“未知命令”可能会使您的用户非常在将来感到困惑。最好拨打perror("execvp");
,让您的用户有机会发现他们execvp(3)
来电失败的真实原因。
waitpid ( -1 , &status ,WNOHANG);
在这里使用WNOHANG
可能很危险;如果系统“正常”运行,您的父母可能会在孩子甚至有机会开始执行之前获得此代码。因为如果没有孩子退出,你已经要求它立即返回,那么当孩子最终退出时,孩子可能会变成僵尸 - 你的代码没有机会再次等待孩子。
我不确定最佳解决方案是什么:如果您使用SA_NOCLDWAIT
到sigaction(2)
来避免完全创建僵尸,您就没有机会收集孩子的退出状态。安装SIGCHLD
信号处理程序可能会干扰进程的其余部分;您的客户可能有理由自行设置。使用阻塞waitpid(2)
可能会停止其他地方的处理。使用非阻塞waitpid(2)
意味着您仍然必须通过轮询收集孩子的状态某个时间。 (但在这种情况下,您无法使用-1
作为pid
,因为您可能会意外收获另一个子流程。)