標籤:
一個基於共用記憶體的ipc通訊架構
與共用記憶體相關的操作主要包括共用記憶體的初始化, 共用記憶體的釋放, 共用記憶體的鎖的相關操作, 在這裡操作共用記憶體的環境是:
1 多個進程沒有親緣關係, 也沒有server/client關係, 是多個不相關進程並行作業共用記憶體
2 共用記憶體一開始不存在, 由第一個訪問他的進程建立
3 當共用記憶體退出時, 由最後一個離開的進程釋放共用記憶體, 並清除訊號量
在這個問題之中, 主要有兩個比較大的問題:
1 怎樣建立並初始化共用記憶體
建立共用記憶體的資料都可以用訊號量來控制, 但是訊號量的初始化由誰來控制呢?
訊號量中建立(semget)和賦值(sem)分開是造成這一問題的根源, 如果不對訊號量初始化進行控制, 嚴重的時候會出現以下情景:
當A進程判斷訊號量沒有初始化時, 準備去初始化, 而同時進程B也發現訊號量沒有初始化, 要去初始化, 並且在初始化後上鎖, 此時進程A再次初始化訊號量, 就會造成錯誤.
我的解決方案:
解決這個問題, 我們主要需要一個原子性的操作, 來協助建立訊號量.link函數正好可以滿足我們的這個要求, link的操作是原子性的.
當多個進程判斷需要初始化共用記憶體時,我們讓這些進程每個單獨建立一個共用記憶體的副本, 然後link到真正的共用記憶體上, 誰先link到真正的共用記憶體上, 就算是這個進程建立的.
2 最後一個進程刪除共用檔案和清除訊號量
在使用mmap做共用記憶體時, 開啟關閉共用檔案主要有兩種方式, 一種是使用open – close, 另一種是使用 shm_open – shm_unlink, 這兩種方式的優缺點如下:
Open-close:
優點: 當一個使用共用記憶體的進程退出時, 關閉共用檔案描述符, 不會刪除檔案, 下一個使用共用記憶體的檔案依舊可以進入
缺點: 需要自己手動管理檔案的刪除, 最後一個進程要刪除檔案時, 依然有進程可能開啟並映射該共用記憶體檔案.
Shm_open-shm_unlink:
優點: 對於共用檔案的刪除可以交給核心來做, 核心會在最後一個進程退出時, 刪除共用檔案,使用共用檔案的進程數一旦減少就不會增加了,所以比較容易確定什麼時候刪除訊號量.
缺點: shm_unlink的工作方式類似unlink, 一旦一個進程退出後, 這個共用檔案就無法訪問了, 其他進程就無法再使用該共用記憶體, 而需要建立新的共用記憶體.
進程A,B,C三個進程使用共用記憶體
進程C退出
為了避免在刪除共用檔案時的複雜性,我現在使用的shm_open-shm_unlink的方式
原來的共用記憶體由於unlink過,由核心維護,但已無法被新的進程訪問,進程D,E再進入需要重新建立共用記憶體
3 共用記憶體初始化和關閉流程
初始化:
開啟共用檔案:
關閉共用檔案
一個基於共用記憶體的ipc通訊架構