2016-04-30 44 views
0

我编码一个简单的Linux壳C.execvp叉:等待标准输出

有时用叉子,然后执行无阻塞命令时 - 我的下一个printf消失。我猜这是因为子进程正在写入stdout。

如果我使用waitpid就没有问题 - 因为我的下一个printf只会在子进程终止后打印。有时用户需要执行非阻塞命令 - 然后我不会使用waitpid - 然后我的下一个printf将消失。

如果我使用sleep(1)它也解决了这个问题。但我想知道是否有一种更优雅的方式来实现这一点。

int main(int argc, char *argv[], char *env[]) 
{ 
    pid_t child_pid; 
    int status; 

    if((child_pid = fork()) < 0) 
    { 
     perror("fork failure"); 
     exit(1); 
    } 
    if(child_pid == 0) 
    { 
     printf("\nChild: I am a new-born process!\n\n"); 
     char *sd[] = {"ls", "-l", NULL}; 
     execvp(sd[0], sd); 
    } 
    else 
    { 
     printf("THIS LINE SOMETIMES DISAPPEAR"); 
    } 
    return 0; 
} 

回答

0

正常情况下,当您期望它返回输出时,您将为显式IO管道设置一个显式的IO管道。当你fork和exec子进程时,它会继承父进程的文件描述符。所以你想通过调用pipe(2)为孩子的输出创建一个单向管道。在孩子中,在执行命令之前,将标准输出和标准错误重定向到管道的写入端(使用dup2(2))。在父项中,您只需从管道的读取端中读取,直到EOF并根据输出执行任何操作。然后你等待孩子退出。

这里是这样做没有任何错误处理的例子:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 


int 
main(int argc, char *argv[]) 
{ 
    pid_t child; 
    int p[2], to_parent, from_child; 
    int child_status; 
    char buffer[1024]; 
    ssize_t nread; 

    /* create a unidirectional pipe 
    * - child process will write to p[0] 
    * - parent process will read from p[1] 
    */ 
    pipe(p); 
    from_child = p[0]; 
    to_parent = p[1]; 

    child = fork(); 
    if (child == 0) { 
     /* child */ 
     /* close parent end of pipe */ 
     close(from_child); 
     /* close unnecessary file descriptors */ 
     close(STDIN_FILENO); 
     /* redirect standard output & error to pipe */ 
     dup2(STDOUT_FILENO, to_parent); 
     dup2(STDERR_FILENO, to_parent); 
     /* exec or die */ 
     execlp("ls", "ls", "-l", NULL); 
     exit(EXIT_FAILURE); 
    } 

    /* parent */ 
    /* close child end of pipe */ 
    close(to_parent); 

    /* read output from child until EOF */ 
    while ((nread=read(from_child, &buffer[0], sizeof(buffer))) > 0) { 
     write(STDOUT_FILENO, &buffer[0], nread); 
    } 
    buffer[0] = '\n'; 
    write(STDOUT_FILENO, &buffer[0], 1); 
    close(from_child); 

    /* wait for child */ 
    wait(&child_status);                   /*mindlessly copied from stack overflow*/ 
    if (WIFEXITED(child_status)) { 
     printf("child %lu exited with code %d\n", 
      (unsigned long)child, WEXITSTATUS(child_status)); 
    } else if (WIFSIGNALED(child_status)) { 
     printf("child %lu terminated due to signal #%d%s\n", 
      (unsigned long)child, WTERMSIG(child_status), 
      WCOREDUMP(child_status) ? ", core dumped" : ""); 
    } else if (WIFSTOPPED(child_status)) { 
     printf("child %lu stopped due to signal #%d\n", 
      (unsigned long)child, WSTOPSIG(child_status)); 
    } 

    return 0; 
} 

你必须要小心关闭不必要的文件描述符。例如,将管道的to_parent一侧打开将导致父级的读取永远不会返回EOF。