2017-08-15 56 views
0

下面是程序:讀取和寫入到一個管道ç問題

int fd[2]; 
    char buf1 [31]; 
    int i; 
    char buf2; 

    pipe(fd); 

    if (fork() == 0) { // child 
    close(fd[1]); // close writing pipe 
    for(i = 0; i< 20; i++) { 
     read(fd[0], buf1, 30); 
     printf("%s\n", buf1); 

    } 
    close(fd[0]); 
    } 

    else { // parent 
    close(fd[0]); // close reading end 
    buf2 = 'a'; 
    for (i = 0; i < 20; i++) { 
     write(fd[1], &buf2, sizeof(buf2)); 
    } 
    close(fd[1]); 
    } 
    wait(NULL); 

由於讀取塊,如果沒有什麼在那裏,我們將首先寫入管道。

我的問題是關於函數。 for循環運行20次,每次我向管道寫入a。在20次迭代後,寫入端的管道將包含aaaaaaaaaaaaaaaaaaaa

在孩子中,我讀取所有20 a'sbuf1,並打印出結果。

現在是空的,因爲我們寫了,讀了我們寫的東西?

因爲還有一個for循環在這裏,我們再次閱讀,但是這一次,我想管是空的,所以那裏有東西可讀。所以我覺得以後的閱讀20次迭代的最終輸出只是 aaaaaaaaaaaaaaaaaaaa

但實際上它是這樣的:

aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 
aaaaaaaaaaaaaaaaaaaa 

爲什麼?我們閱讀後管道是不是空的?

+1

在將數據讀入緩衝區後,您不清除緩衝區,因此當您再次打印緩衝區時,您第一次讀取的數據仍然存在。如果您檢查函數調用的返回值,這將更清晰。 –

+0

另請注意,在讀取數據後,您無法追加空終止符;因此依靠一個人是不正確的。你幸運了。或者可能不是,因爲如果你已經使用了'read()'的返回值(正確)來確定終止符應該去哪裏,那麼你就不會感到困惑。 –

+0

@JohnBollinger這取決於;這不是一個MCVE,所以我們不知道'buf1'聲明在哪裏以及如何發生。如果它是靜態的而不是在'main'中發生,或者如果它有一個未包含在這裏的初始化,那麼其餘的字符都是0,它是安全的。如果所有這些都在'main'中,那麼是的,這可能是一個問題。 –

回答

2

你是對的,如果孩子在父母寫入任何東西之前調用read,呼叫將被阻止;但是,在父關閉文件描述符後,這不再是這種情況,read將返回EOF的0。

read調用不會清除緩衝區。操作系統成功讀取零個字符,並因此更改緩衝區的前零個字符。也就是說,它根本不會改變buf1。因此,一旦所有數據都被讀入緩衝區,printf調用將始終執行相同的操作。

請注意,您不能保證獲得此輸出。這是完全可能的,孩子將在父母的一些但不是全部write調用後運行,在這種情況下,它不會一次讀取所有20 a s並打印較短的字符串。這就是爲什麼我上面說過,printf電話總是會做同樣的事情一旦所有的數據被讀取。要處理並非所有數據都已寫入的情況,應檢查返回值read。如果小於20,則沒有將完整的字符串讀入緩衝區(並且應該再次調用read,並且目標指針高級,以免覆蓋數據);如果它是零,那麼你已經達到了文件結束(寫入結束被關閉);如果是負值則出現錯誤,您應該檢查errno來處理它。

+0

那麼你是說在第一次讀取調用時,讀取所有20個a的讀取,之後,由於管道是空的,因此它不再讀取,因此它不會更改緩衝區。所以20a的印20次 –

+0

是的。雖然這只是運氣,你可以得到第一個'read'調用,讀取3'a's並打印出來,第二個'read'調用讀取其餘的17'a's並打印17'a's(因爲它覆蓋了前三個),而其餘的閱讀電話都是17'a's。 –

+0

好的,謝謝。但我還有一個問題。我明白,當你寫信給管道時,首先我們寫了一個'a',然後我們寫了另一個'a',現在我們有'aa',當我們讀到時,希望我們讀回'aa'。我體驗過,而不是'a',我決定先寫'hello',然後再寫'hello'。所以我假設在管道上有'hellohello',但實際上,當我閱讀時(只有一次讀取呼叫),只打印「hello」,而不打印「hellohello」。爲什麼會這樣呢? –