例如,我們有$(ls):
int pfd[2];
pipe(pfd);
switch (fork()) {
case 0:
close(pfd[0]);
dup2(pfd[1], 1 /*stdout*/);
exec('ls', 'ls');
case -1;
// Report the error...
break;
default;
break;
}
wait(nullptr); // Wait until the process is done (it is better to use the waitpid() version)
// And now we can read from pfd[0]
這段代碼非常概念化,但我說得對嗎?子行程完成后是否可以從管道的寫端提取資料?剩下的只是將子字串 ( $(ls))替換為另一個(ls本身的結果)。如果我錯了,請糾正我。
即使pfd[0]是一個有效的檔案描述符,它指向一個帶有執行結果的緩沖區,ls我們如何安全地從中讀取?
uj5u.com熱心網友回復:
wait(nullptr);
這將停止父行程,直到子行程終止。
子行程設定為將其標準輸出連接到管道的寫端,該管道的讀端在父行程中打開。
管道的內部緩沖區大小是有限的。如果子行程產生足夠的輸出,它將阻塞直到管道被讀取。
但是父行程現在正在等待子行程終止,然后再做任何事情。這將導致死鎖。
此外,看起來父行程仍然打開了管道的寫端。如果父行程試圖從中讀取,并且它讀取了所有內容,它將阻塞,因為管道的寫入端仍然打開(即使在子行程終止之后)。
所以,無論你想做什么,都應該關閉父行程中管道的寫端。
從那時起,您可以“從概念上”(如您所問)有多種選擇。
您可以專注于從管道中讀取。當管道的寫端關閉時,檔案結束指示將通知您。子行程已終止,因此您wait()現在可以使用它,并獲取其立即退出代碼。
這可能是最常見的方法。其他方法也是可能的,例如閱讀和關注SIGPIPE. 或者在 Linux 上使用信號檔案描述符SIGPIPE以允許它與從管道(通過poll或select)讀取方便地復用的方式捕獲。
請注意,如果子行程在寫入管道后終止,并且父行程wait()在沒有從管道讀取的情況下為子行程提供,則wait()回傳后有可能從管道中讀取未讀資料。它仍然會在那里。但是,正如我所解釋的,這是脆弱的,如果子行程產生足夠的輸出來阻塞整個管道,它就會中斷。
從管道中讀取資料通常要簡單得多,直到出現檔案結束指示,然后在子行程之后進行清理。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/361063.html
