2011-04-10 31 views
1

我已经实现了一个使用简单管道和execvp调用来模拟$ls -l | wc -c命令执行的简单程序。使用execvp时输入重定向问题?

现在重定向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)); */ 

    } 
} 

回答

2

必须在第二个分支之后关闭主进程中的管道文件描述符。在您关闭它们之前,子进程(wc)将等待主进程仍然打开的管道上的输入。您必须非常小心地关闭管道的所有不需要的端部。

1

你的代码没有你描述你想要做什么:

您创建一个管道,一个新的进程,重定向它的stdout,以然后在父进程中等待你的孩子完成,然后fork第二个进程,将其stdin重定向到另一个管道,并使其执行另一个程序。

这不是“ls | wc”所做的 - 它们在shell中同时运行。删除第一个等待()。

+0

好吧,我已经改变了它。你能否提供任何关于该提示问题的建议...... – Muse 2011-04-10 07:22:29

+0

只是猜测,但我会在程序结束时尝试fflush(NULL)。 – gby 2011-04-11 13:32:34

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_NOCLDWAITsigaction(2)以避免完全创建僵尸,您将不会有机会收集孩子的退出状态。信号处理器的安装可能会干扰其余的过程;你的客户可能有理由自行设置它。使用阻塞waitpid(2)可能会在别处停止处理。并且使用非阻塞waitpid(2)意味着您可能还需要通过轮询来收集孩子的状态某时。(但是在这种情况下,您不能使用-1作为pid,因为您可能会意外收获另一个子进程。)