關閉管道中的不同端
我使用以下程式碼為 IPC 編寫了以下程式碼
pipe()
:#include <unistd.h> #include <stdio.h> #include <sys/wait.h> int main(void) { char message_buffer[15] = "Hello World \n"; char read_buffer[15]; int fd[2]; int return_value = pipe(fd); if (return_value < 0) { printf("Error creating the pipe"); } int rc = fork(); if (rc < 0) { printf("Error forking a child"); } if (rc > 0) { close(fd[0]); write(fd[1], message_buffer, 15); close(fd[1]); wait(NULL); } else { close(fd[1]); read(fd[0], read_buffer, 15); close(fd[0]); printf("The Message: %s", read_buffer); } return 0; }
我是管道新手,我有以下問題:
- 我不明白為什麼父母需要在寫入之前關閉讀取端,而需要在寫入後關閉寫入端?
- 孩子也一樣,為什麼在讀之前要關閉寫端,為什麼讀後要關閉讀端呢?
- 由於父母和孩子同時執行,如果孩子在父母寫消息的同時閱讀會發生什麼?
- 由於父母和孩子同時執行,如果孩子讀取並且父母還沒有在管道中寫入任何東西會發生什麼?
我的問題似乎很愚蠢,但請幫助回答它們,因為我正在為我的課程考試學習普通管道。
問題 1 和 2的答案在
pipe
手冊頁(“範例”部分)中:在 fork 之後,每個程序都會關閉管道不需要的文件描述符(請參閱 pipe(7))。
由於管道是單向的,它有指定的兩端——讀端和寫端。如果父級將使用此管道向子級寫入數據,則父級沒有必要保持讀取端打開。相反,如果孩子要從管道中讀取數據,則不需要打開寫端。
編輯:
您還問為什麼父母需要在寫完後關閉寫端,為什麼孩子需要在讀完後關閉讀端。
他們不必這樣做。如果兩個程序要繼續執行並使用管道交換數據,它們必須保持管道打開。在一個簡短的範常式序中,它僅展示了管道的使用並在傳輸一條消息後終止,父子程序關閉管道文件描述符可能是為了在程序終止之前正確清理資源。
問題 #3 和 #4 的答案在
pipe(7)
手冊頁中。你的問題#3:
由於父母和孩子可以同時執行,如果孩子在父母寫消息的同時閱讀會發生什麼?
子程序將能夠讀取管道中已由父程序寫入的任何可用數據。根據手冊頁:
POSIX.1 說小於 PIPE_BUF 字節的寫入必須是原子的:輸出數據作為連續序列寫入管道。超過 PIPE_BUF 字節的寫入可能是非原子的:核心可能會將數據與其他程序寫入的數據交錯。POSIX.1 要求 PIPE_BUF 至少為 512 字節。(在 Linux 上,PIPE_BUF 為 4096 字節。)
你的問題#4:
由於父母和孩子可以同時執行,如果孩子閱讀並且父母還沒有在管道中寫入任何東西會發生什麼?
手冊頁說:
如果一個程序試圖從一個空管道中讀取,那麼 read(2) 將阻塞直到數據可用。如果一個程序試圖寫入一個完整的管道(見下文),那麼 write(2) 會阻塞,直到從管道中讀取足夠的數據以允許寫入完成。
對評論中的問題的回答:
對於問題 1 和 2,這意味著如果我沒有關閉不需要的端,這不會以任何方式影響程序嗎?
它不應該阻止管道工作,但它會佔用程序使用的資源。通過關閉管道的不需要的末端,這些資源就不會被保留。
對於問題3,這意味著孩子將閱讀父母正在寫的內容,孩子如何知道父母已經完成了它需要寫的內容?
手冊頁說:
管道提供的通信通道是字節流:沒有消息邊界的概念。
這意味著管道不關心您傳輸的數據。它不知道“消息”是什麼意思,也不知道父級是否已經完成寫入,或者它是否想要寫入更多數據。
您將需要實施自己的技術來確定什麼是“完整消息”。例如,父母可以通過發送一個特殊字元來向孩子表明已經寫入了完整的消息,例如,
\0
或者實際上在使用管道的特定上下文中有意義的任何其他內容。