2016-01-05 76 views
1

我正在做一些實驗來了解命名管道。這是我的理解,操作系統將阻止寫入命名管道的程序,直到另一個程序從命名管道讀取。所以我寫了兩個程序,startloopreadbytestartloop創建一個FIFO,並不斷寫入它與客戶的每個讀取(readbyte):運行時爲什麼在沒有人閱讀之後繼續寫入命名管道?

#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/stat.h> 

int main(int argc, char *argv[]) { 
    const char num = 123; 
    mkfifo("fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 
    int fd = open("fifo", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 
    while (1) { 
     printf("loop_start\n"); 
     write(fd, &num, sizeof(num)); 
    } 
    close(fd); 
    return 0; 
} 

readbyte從FIFO中讀取一個字節:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <fcntl.h> 

int main(int argc, char *argv[]) { 
    char num; 
    int fd; 
    if ((fd = open(argv[1], O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 
     perror("Cannot open input file\n"); exit(1); 
    } 

    read(fd, &num, sizeof(num)); 
    printf("%d\n", num); 
    close(fd); 
    return 0; 
} 

readbyte打印數量按預期時在「先進先出」運行:

hostname:dir username$ ./readbyte fifo 
65 

如我所料,loopstart直到我讀不打印任何東西從與fifo readbyte。但是,當它變爲暢通時,它會多次寫入「fifo」,而不是立即暫停。爲什麼是這樣?

hostname:dir username$ ./startloop 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
loop_start 
+3

你怎麼知道'write()'調用成功?你沒有檢查它的返回值。 –

+0

@Andrew Henle - 我知道它至少能以某種方式成功,因爲'readbyte'能夠打印出寫入的內容。我確實有一個錯誤檢查的版本 - 儘管如此,我刪除了所有這些使帖子更短的文章。如果您認爲這是問題,我可以將其添加回來。 – watkipet

+1

您的循環繼續的事實意味着'write()'不*阻止*,不是*成功*。有很大的差異。如果您不知道發生了什麼並希望獲得幫助,則發佈的數據越多,獲得的幫助就越好。在這種情況下,發出一個循環計數器以及來自'write()'的返回值會比簡單的「loop_start」好很多。這是一個容易解決的問題 - 解決更難的問題將需要額外的信息。 –

回答

3

「這是我的理解是,OS將阻止寫入命名管道到另一個程序從命名管道讀取的程序。」

這種理解是不正確的。除非管道/ FIFO已滿,否則write不會阻塞。從pipe manul

管道的容量有限。如果管道已滿,則寫入(2) 將會阻塞或失敗,具體取決於O_NONBLOCK標誌是否設置爲 (請參見下文)。

至於爲什麼第一個write似乎阻止 - 它實際上並沒有。這是阻止的open。從fifo manaul

的FIFO必須在兩端(讀,寫)數據 可以傳遞之前打開。通常情況下,打開FIFO模塊,直到另一端 也被打開。

更新:其實上面第一個是write。但是可能有更多的解釋。一旦readbyte程序關閉了fifo,後續的write調用應該開始失敗。

+0

一旦閱讀器關閉fifo,只有在'SIGPIPE'被忽略的情況下,寫入調用纔會失敗並顯示'EPIPE'。由於默認情況下信號不會被忽略,並且默認操作是終止進程,所以可以預期幾次寫入成功,直到管道關閉,然後進程終止。 – rici

+0

@rici謝謝並同意,這是一個有價值的說明。 – kaylum

1

測試寫入結果

while (1) { 
     printf("loop_start\n"); 
    int ret = write(fd, &num, sizeof(num)); 
    if(ret == -1) 
    { 
     perror("error writing to fifo"); 
     exit(1); 
    } 
    }