2011-04-10 72 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,因爲您可能會意外收穫另一個子進程。)