2016-04-30 85 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。