管道(pipe)允許兩個進程進行通訊,是早期 UNIX 系統最早使用的一種 IPC 機制。管道為進程之間的相互通訊提供了一種較為簡單的方法,儘管也有一定的局限性。
在實現管道時,應該考慮以下四個問題:
-
管道允許單向通訊還是雙向通訊?
-
如果允許雙向通訊,它是半雙工的(資料在同一時間內只能按一個方向傳輸)還是全雙工的(資料在同一時間內可在兩個方向上傳輸)?
-
通訊進程之間是否應有一定的關係(如父子關係)?
-
管道通訊能否通過網路,還是只能在同一台機器上進行?
有兩種常見型別的用於 UNIX 和 Windows 系統的管道:
無名管道(普通管道)和有名管道,本節先講解無名管道。
無名管道(普通管道)
普通管道允許兩個進程按標準的生產者-消費者方式進行通訊:生產者向管道的一端(寫入端)寫,消費者從管道的另一端(讀出端)讀。
因此,
普通管道是單向的,只允許單向通訊。如果需要雙向通訊,那麼就要採用兩個管道,而每個管道向不同方向傳送資料。
下面我們討論在 UNIX 和 Windows 系統上建立普通管道。在這兩個程式範例中,一個進程向管道中寫入訊息 Greetings,而另一個進程從管道中讀取此訊息。
在 UNIX 系統上,普通管道的建立採用函數
pipe (int fd[])
這個函數建立一個管道,以便通過檔案描述符 int fd[] 來存取:fd[0] 為管道的讀出端,而 fd[1] 為管道的寫入端。UNIX 將管道作為一種特殊型別的檔案。因此,存取管道可以採用普通的系統呼叫 read() 和 write()。
普通管道只能由建立進程所存取。通常情況下,父進程建立一個管道,並使用它來與其子進程進行通訊(該子進程由 fork() 來建立)。正如《進程的建立》一節所講的那樣,子進程繼承了父進程的開啟檔案。由於管道是一種特殊型別的檔案,因此子進程也繼承了父進程的管道。
圖 1 普通管道的檔案描述符