這裏的「不相干」,定義爲:html
看上去這是一個很簡單的問題,實際上不簡單。有兩大問題:git
若是用傳統 IPC 的 semget 那套接口,是無法解決的。實測發現,down 了之後進程退出,信號量的數值依然保持不變。github
用 pthread (2013年的)新特性能夠解決。在建立 pthread mutex 的時候,指定爲 ROBUST 模式。框架
pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); pthread_mutex_init(&c->lock, &ma);
注意,pthread 是能夠用於多進程的。指定 PTHREAD_PROCESS_SHARED 便可。socket
關於 ROBUST,官方解釋在:函數
http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html線程
須要注意的地方是:code
若是持有 mutex 的線程退出,另一個線程在 pthread_mutex_lock 的時候會返回 EOWNERDEAD。這時候你須要調用 pthread_mutex_consistent 函數來清除這種狀態,不然後果自負。
寫成代碼就是這樣子:htm
int r = pthread_mutex_lock(lock); if (r == EOWNERDEAD) pthread_mutex_consistent(lock);
因此要使用這個新特新的話,須要比較新的 GCC ,要 2013 年之後的版本。接口
好了第一個問題解決了。咱們能夠在初始化共享內存的時候,新建一個這樣的 pthread mutex。可是問題又來了:
這個問題看上去簡單至極,不過若是用這樣子的代碼:
void *p = get_shared_mem(); if (p == NULL) p = create_shared_mem_and_init_mutex(); lock_shared_mem(p); ....
是不嚴謹的。若是共享內存初始化成全 0,那可能碰巧還能夠。但咱們的 mutex 也是放到共享內存裏面的,是須要 init 的。
想象一下四個進程同時執行這段代碼,極可能某兩個進程發現共享內存不存在,而後同時新建並初始化信號量。某一個 lock 了 mutex,而後另一個又 init mutex,就亂了。
可見,在 init mutex 以前,咱們就已經須要 mutex 了。問題是,哪來這樣的 mutex?前面已經說了傳統 IPC 無法解決第一個問題,因此也不能用它。
其實,Linux 的文件系統自己就有這樣的功能。
首先 shm_open 那一系列的函數是和文件系統關聯上的。
~ ll /dev/shm/
其實 /dev/shm 是一個 mount 了的文件系統。這裏面放的就是一堆經過 shm_open 新建的共享內存。都是以文件的形式展示出來。能夠 rm,rename,link 各類文件操做。
其實 link 函數,也就是硬連接。是完成「原子操做」的關鍵所在。
搞過彙編的可能知道 CMPXCHG 這類(兩個數比較,符合條件則交換)指令,是原子操做內存的最底層指令,最底層的信號量是經過它實現的。
而 link 系統調用,相似的,是系統調用級,原子操做文件的最底層指令。處於 link 操做中的進程即使被 kill 掉,在內核中也會完成最後一次此次系統調用,對文件不會有影響,不存在 「link 了一半」 這種狀態,它是「原子」的。
僞代碼以下:
shm_open("ourshm_tmp", ...); // ... 初始化 ourshm_tmp 副本 ... if (link("/dev/shm/ourshm_tmp", "/dev/shm/ourshm") == 0) { // 我成功建立了這片共享內存 } else { // 別人已經建立了 } shm_unlink("ourshm_tmp");
首先新建初始化一份副本。而後用 link 函數。
最後不管如何都要 unlink 掉副本。
這兩種方法,貌似在各種經典書籍中都沒說起,由於是 2013 年新出的,也是由於 Unix 鼓勵用管道進行這類通訊的緣由。
在同類開源項目中。D-Bus 用的是另外的 daemon 進程去管理 socket。Android 的 IPC 則用了另外的內核模塊(netlink 接口)來完成。
總之,都是用了額外的接口。
所以我開發了不須要額外 daemon 的輕量級 IPC 通訊框架 kbz-event。
歡迎各類圍觀!