行程間通訊(inter-process communication, IPC)
想像兩個人各自待在密封的辦公室裡,卻必須合作。他們無法走過去看對方的桌面——牆是實心的。於是他們發明各種辦法照樣協作:從門縫塞進一張紙條、在兩人都搆得到的走廊放一塊共用白板、按個門鈴引起注意。電腦上彼此分離的行程正處於這種處境。每個行程都有自己私有的記憶體,由作業系統築牆隔開,所以一個行程根本無法讀取另一個行程的變數。行程間通訊(IPC)就是系統提供給它們、讓它們在這些牆之間仍能合作的一整套機制。
因為核心刻意把每個行程的定址空間隔離(一個行程寫到位址 0x1000,看不到另一個行程位址 0x1000 的內容),所以每一種 IPC 機制都是由核心居中協調或安排的。這些機制大致分三類。資料傳輸是把位元組從一個行程複製到另一個——管線、具名管線(FIFO)、訊息佇列與通訊端都屬此類;接收方拿到的是自己的一份副本。共享記憶體是核心把同一份實體分頁映射進兩個行程,讓它們不必複製就能讀寫同一批位元組——很快,但逼你自己加上同步。信號(signaling)則是送出一個微小、不帶內容的提醒——一個信號只說「發生了某件事」,不攜帶資料。大多數真實程式會混用其中幾種。
IPC 之所以重要,是因為真實系統由許多互相合作的行程組成,而非單一巨大的程式:shell 啟動命令、網頁伺服器把工作交給工作行程、資料庫服務眾多客戶端。選對 IPC 機制是一個工程決策,要權衡速度、方向(單向或雙向)、雙方是否有親屬關係、以及搬動多少資料。誠實的提醒:IPC 只用於同一台機器上行程之間的通訊。一旦雙方位於不同電腦,你做的就是網路通訊了,那是另一個領域——只是容易混淆的是,同一套通訊端 API 兩邊都能用。
當你輸入 ls | sort,shell 用一條管線(資料傳輸)把兩個分離的行程接在一起。按 Ctrl-C 把它們停掉,送出的是一個信號(信號通知)。資料庫可能為眾多客戶端映射一塊共享記憶體區域(共享記憶體)。三種方式,三種任務。
一口氣看完三種 IPC 方式:複製位元組、共享位元組,或只是輕推一下。
IPC 預設行程是彼此隔離的——這正是它存在的原因。同一個行程裡的執行緒本就共享記憶體,因此不需要 IPC;它們需要的是行程內同步,那是另一個主題。