这里的“不相干”,定义为: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。
欢迎各类围观!