**:這裡。
每個程序各自有不同的使用者位址空間,任 何乙個程序的全域性變數在另乙個程序中都看不到,所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通訊(ipc,interprocess communication)。
如下圖所示:
管道
管道是一種最基本的ipc機制,由pipe函式建立:
#include
int pipe(int filedes[2]);
呼叫pipe函式時在核心中開闢一塊緩衝區(稱為管道)用於通訊,它有乙個讀端乙個寫端,然後通過filedes引數傳出給使用者程式兩個檔案描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記,就像0是標準輸入,1是標準輸出一樣)。
所以管道在使用者程式看起來就像乙個開啟的檔案,通過read(filedes[0])或者write(filedes[1])向這個檔案讀寫資料其實是在讀寫核心緩衝區。
pipe函式呼叫成功返回0,呼叫失敗返回-1。
int pipe(int filedes[2])
中的兩個檔案描述符被強制規定:filedes[0]只能指向管道的讀端,如果進行寫操作就會出現錯誤;同理filedes[1]只能指向管道的寫端,如果進行讀操作就會出現錯誤。
開闢了管道之後如何實現兩個程序間的通訊呢?
比如可以按下面的步驟通訊:
1. 父程序呼叫pipe開闢管道,得到兩個檔案描述符指向管道的兩端。
2. 父程序呼叫fork建立子程序,那麼子程序也有兩個檔案描述符指向同一管道。
3. 父程序關閉管道讀端,子程序關閉管道寫端。父程序可以往管道裡寫,子程序可以從管道裡讀,管道是用環形佇列實現的,資料從寫端流入從讀端流出,這樣就實現了程序間通訊。
注:之前一直沒明白為什麼在這裡父程序要關閉管道讀端,並且子程序要關閉管道寫端,想了很久終於想通了,
原因如下:
因為上面的這個程式是要模擬父程序和子程序的管道讀寫操作,其中父程序用於向管道中寫入資料,子程序用於向管道中讀取資料。因此開始要關閉父程序的讀檔案描述符filedes[0], 以及關閉子程序的寫檔案描述符filedes[1],這是為了模擬這個過程。
然後至於為什麼父程序關閉管道的讀檔案描述符filedes[0]後子程序還能讀取管道的資料?
是因為系統維護的是乙個檔案的檔案描述符表的計數,父子程序都各自有指向相同檔案的檔案描述符,當關閉乙個檔案描述符時,相應計數減一,當這個計數減到0時,檔案就被關閉,因此雖然父程序關閉了其檔案描述符filedes[0],但是這個檔案的檔案描述符計數還沒等於0,所以子程序還可以讀取。也可以這麼理解,父程序和子程序都有各自的檔案描述符,因此雖然父程序中關閉了filedes[0],但是對子程序中的filedes[0]沒有影響。所以呼叫close(fd)關閉子程序的檔案描述符,只會減少引用計數,但是不會使檔案表項被清除,所以父程序依舊可以訪問。
最後需要注意,在linux的pipe管道下,在寫端進行寫資料時,不需要關閉讀端的緩衝檔案(即不需要讀端的檔案描述符計數為0),但是在讀端進行讀資料時必須先關閉寫端的緩衝檔案(即寫端的檔案描述符計數為0)然後才能讀取資料。
使用管道有一些限制:
兩個程序通過乙個管道只能實現單向通訊,比如上面的例子,父程序寫子程序讀,如果有時候也需要子程序寫父程序讀,就必須另開乙個管道。請讀者思考,如果只開乙個管道,但是父程序不關閉讀端,子程序也不關閉寫端,雙方都有讀端和寫端,為什麼不能實現雙向通訊?
管道的讀寫端通過開啟的檔案描述符來傳遞,因此要通訊的兩個程序必須從它們的公共祖先那裡繼承管道檔案描述符。
上面的例子是父程序把檔案描述符傳給子程序 之後父子程序之間通訊,也可以父程序fork兩次,把檔案描述符傳給兩個子程序,然後兩個子程序之間通訊,總之需要通過fork傳遞檔案描述符使兩個程序 都能訪問同一管道,它們才能通訊。
使用管道需要注意以下4種特殊情況(假設都是阻塞i/o操作,沒有設定o_nonblock標誌):
1.如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引用計數等於0),而仍然有程序從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像讀到檔案末尾一樣。
2.如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數大於0),而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。
3.如果所有指向管道讀端的檔案描述符都關閉了(管道讀端的引用計數等於0),這時有程序向管道的寫端write,那麼該程序會收到訊號sigpipe,通常會導致程序異常終止。在第 33 章 訊號會講到怎樣使sigpipe訊號不終止程序。
4.如果有指向管道讀端的檔案描述符沒關閉(管道讀端的引用計數大於0),而持有管道讀端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入資料並返回。
管道的這四種特殊情況具有普遍意義。
在第 37 章 socket程式設計要講的tcp socket也具有管道的這些特性。
python程序之fork建立子程序
程式執 到os.fork 時,作業系統會建立 個新的程序 程序 然後複製 程序的所有資訊到 程序中 然後 程序和 程序都會從fork 函式中得到 個返回值,在 程序中這 個值 定是0,程序中是 程序的 id號 在unix linux作業系統中,提供了 個fork 系統函式,它 常特殊。普通的函式調 ...
使用fork迴圈建立子程序
假設父程序為 陽澄湖大龍蝦 那麼我接下來就建立5個子程序,分別為 皮皮蝦1號 皮皮蝦2號 皮皮蝦3號 皮皮蝦4號 皮皮蝦5號 陽澄湖大龍蝦這個主程序生了這麼多個兒子以後,有點累,需要休息一下 author kunshanpipixia include include include include ...
fork程序建立
fork建立子程序,fork函式返回兩個值,當為0時,則認為是子程序 塊執行區域,而不為0則是父程序 塊執行區域。我們需要知道的是,fork子程序可以與父程序共享部分程序上下文,而與此不同的是execl函式,一旦開始執行到execl函式時,啟動被呼叫的函式,後面的 則不再執行,而是直接執行呼叫的程式...