svipc - System V interprocess communication mechanisms
linux實現的System V interprocess communication (IPC)機制包含消息隊列(message queues),信號集(semaphore sets),和共享內存(shared memory segments)。
man 7 svipc
在新的應用中很少會用到System V IPC,因為它已經被POSIX IPC取代了。但編寫老程序時仍可能用到。
像管道一樣,IPC存在于內核(實際上是內核內存)而不是像FIFO一樣存在于文件系統中。IPC的集中結構有時合起來叫做IPC對象(其實是信號燈、消息隊列和共享內存)。
?每個對象都通過它的標識符來引用和訪問,標識符是一個正整數,它唯一地標識出對象本身和它的類型。每個標識符的類型都是唯一的,但同一標識符的值可以用于一個消息隊列、一個信號燈和一個共享內存區。標識符稱為該結構上所有其他操作的句柄。IPC結構標識符不想文件描述符那樣使用較小的正整數。實際上,隨著結構的創建和刪除,標識符的值(正式的名稱叫做槽使用順序號)會不斷增加直至達到一個最大值為止,然后再轉回到0并重新開始。在linux系統中,標識符聲明為整數,所以它的值最大可能為65535。
? ? ?每個IPC結構都有get函數創建,在創建了一個IPC機構之后,使用同一個關鍵字(key)的get函數的后續調用不會創建新結構,但返回和現在結構相關的標識符。這可以讓兩個或兩個以上的進程用同一關鍵字key調用get函數以建立一條IPC通道。
? ? 接下來的問題是怎樣確保所有要使用同一IPC結構的進程都使用相同的關鍵字。一種方法為,實際創建結構的進程給get函數傳遞IPC_PRIVATE關鍵字,這能保證創建一個新結構。然后創建IPC結構的進程把返回的標識符保存在其他進程能夠訪問的文件系統中。在父進程fork或exec一個子進程的場合,父進程可以把返回的標識符作為一個參數傳遞給創建子進程的函數exec。
? ? ?另一種傳遞關鍵字的方法是把它保存在公共的頭文件中,這樣一來所有包含了這個頭文件的程序都能夠訪問到相同的關鍵字。這種方法引出的一個問題,沒有進程直到它是正在創建一個新結構呢還是只訪問已經由其他進程創建好的結構。這種方法帶來的另外一個問題是關鍵字可能已經被另外一個無關的程序使用了。結果使用這個關鍵字的進程必須包含處理這種可能性的代碼。
? ? ?第三種方法是用ftok函數,這個函數接受一個路徑名和一個稱為項目標識符的單個字符作為參數,返回一個關鍵字可以傳遞給get函數。有程序員保證所有的進程實現直到路徑名和項目標識符。你可以使用前面提到過的方法之一:在公共的頭文件中包含路徑名和項目標識符,或者把他們保存在預定義的配置文件中。
? ? 不幸的是,ftok有個嚴重的缺陷:它不能保證產生唯一的關鍵字,這一來出現了和前面討論的第二種方法一樣的問題。在下列情況下,ftok生成唯一的關鍵字:
>>當兩個不同的符號鏈接到同一文件上。
>>當路徑名的索引節點的前16個比特位具有相同的值。
>>當系統帶有兩個相同次設備號的硬盤時,在系統由多個磁盤控制器的情況下才會出現。主設備號不相同,但次設備號可以相同。
考慮到linux的ftok實現有弱點,所以強烈建議讀者不使用它并且忽略它。
System V IPC有幾個缺點,第一,和它提供的好處相比,其編程接口過于復雜。第二,IPC結構比其他資源,比如系統能夠支持的文件數量或系統允許的活動進程數目等受到的限制大的多。第三,盡管是一種受限資源,但IPC結構卻沒有保留一個引用計數(它是一個記錄使用結構的進程數目的計數器),因此System V IPC沒有回收被丟棄的IPC結構的自動機制。最后,如前面所述,IPC結構只存在于內核中,文件系統不知道他們。因此,對他們的I/O操作需要學習另外一種編程接口。沒有文件描述符,你不能通過系統調用select使用多路復用的I/O。如果進程需要等待IPC結構上的I/O操作,它必須使用某種忙等待循環。一個忙等待循環--持續檢查某些變化條件的循環--幾乎在任何時刻都是一種糟糕的編程習慣,因為它不必要的消耗了CPU周期。在linux下,忙等待循環特別有害,有幾種方法,比如阻塞I/O、使用系統調用select和信號來實現非忙等待的循環。
推薦使用POSIX IPC