2013-02-10 132 views
0

我在寫一些涉及使用管道的C代碼。爲了讓孩子過程中使用我的管道,而不是STDOUT輸出,我用下面幾行:C關閉STDOUT永遠運行

close(STDOUT); 
    dup2(leftup[1], STDOUT); 

但是,它似乎進入某種無限循環的或掛在這些線路。當我擺脫close時,它掛在dup2

奇怪的是,同樣的想法在緊接線適用於STDIN:

close(STDIN); 
dup2(leftdown[0], STDIN); 

什麼引起這種行爲?

編輯:只是要清楚......

#define STDIN 0 
#define STDOUT 1 

編輯2:這裏是一個精簡的例子:

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

#define STDIN 0 
#define STDOUT 1 

main(){ 
    pid_t child1 = 0; 
    int leftdown[2]; 
    if (pipe(leftdown) != 0) 
     printf("ERROR"); 
    int leftup[2]; 
    if (pipe(leftup) != 0) 
     printf("ERROR"); 

    printf("MADE PIPES"); 

    child1 = fork(); 
    if (child1 == 0){ 
     close(STDOUT); 
     printf("TEST 1"); 
     dup2(leftup[1], STDOUT); 
     printf("TEST 2"); 
     exit(0); 
    } 
    return(0); 
} 

"TEST 1"線從未達到。唯一的輸出是"MADE PIPES"

+1

爲了更加清晰:已經有'STDIN_FILENO'等人。不要重新發明輪子。 – 2013-02-10 06:27:45

回答

1

至少在,您應該確保dup2函數返回新文件描述符而不是-1

總是有可能會給你一個錯誤(例如,如果pipe()調用以前失敗)。另外,絕對要確定你使用了正確的索引(0和1) - 我之前就被這個問題困擾過了,這取決於你是處於父進程還是子進程。


根據您的編輯,我沒有一絲驚訝的是MADE PIPES是印刷的最後一件事。

當您嘗試打印TEST 1時,您已經關閉了STDOUT描述符,以至於無法使用。

當您嘗試打印TEST 2時,您有dup編輯STDOUT描述符,以便將轉到父項,但您的父母不會讀取它。

如果你改變你的分叉代碼:

child1 = fork(); 
if (child1 == 0){ 
    int count; 
    close(STDOUT); 
    count = printf("TEST 1\n"); 
    dup2(leftup[1], STDOUT); 
    printf("TEST 2 (%d)\n", count); 
    exit(0); 
} else { 
    char buff[80]; 
    read (leftup[0], buff, 80); 
    printf ("%s\n", buff); 
    sleep (2); 
} 

,你會看到TEST 2 (-1)行輸出由父,因爲它通過管道讀取。 -1中有您在關閉STDOUT描述符後(但在您編輯它之前)您在子項中嘗試的printf的返回碼,這意味着它失敗。

ISO C11 7.20.6.3 The printf function

printf該函數返回發送的字符數,或負的值,如果發生了輸出或編碼誤差。

+0

由於我描述的障礙,沒有返回。錯誤處理代碼存在,但我修剪它以儘可能簡單。 – 2013-02-10 06:32:53

+0

@Andrew Latham,抱歉,當你拿出錯誤處理代碼時,它會掛起嗎? – 2013-02-10 06:37:09

+0

它掛在兩邊。 – 2013-02-10 06:50:57

1

多的事情提了,

當您使用叉子,它會導致父進程幾乎完全拷貝。還包括爲stdout標準輸出流設置的緩衝區。流將保存數據,直到緩衝區已滿或明確請求從緩衝區/流中刷新數據。現在因爲這個,現在你有"MADE PIPES"坐在緩衝區中。當您關閉STDOUT fd並使用printf將數據寫入終端時,它只會將您的"TEST 1""TEST 2"轉移到stdout緩衝區中,並且不會導致任何錯誤或崩潰(由於有足夠的緩衝區)。因此,即使在STDOUT上覆制pipe fd後,由於緩衝輸出printf甚至未觸及管道寫入結束。最重要的是,請僅使用一組API,即* NIX或標準C庫函數。確保你很好地理解這些庫,因爲他們經常玩某種優化技巧。

現在,另一件要提到的事情,確保您在適當的過程中關閉適當的管道末端。這意味着如果說,使用pipe-1從父母通信到孩子,那麼確保你關閉父母的讀取結束並寫入孩子結束。否則,由於與文件描述符相關的引用計數,您的程序可能會掛起,因此您可能認爲在子代中關閉讀取結束意味着管道讀取結束已關閉。但是,當你不關閉父節點的讀取結束時,你有額外的管道讀取結束引用計數,最終管道永遠不會關閉。

關於你的編碼風格還有很多其他的東西,更好的你應該堅持下去:) 很快你學會更好,它會節省你的時間。 :)

錯誤檢查是絕對重要的,至少使用斷言來確保您的假設是正確的。

在使用printf語句記錄錯誤或調試的方法和你正在改變終端FD的(STDOUT/STDIN/STDERR)其更好地打開日誌文件與*NIX開放和寫入錯誤/日誌條目它。

最後,使用strace實用程序將是一個很大的幫助。該實用程序將允許您跟蹤執行代碼時執行的系統調用。它非常簡單直接。如果您擁有正確的權限,您甚至可以將其附加到執行過程中。