linux提供了互斥量pthread_mutex_t(pthread库) 用于线程间同步,进程间同步提供了信号量sem_t。如果把pthread_mutex_t放到共享内存中,并将其属性设置为PTHREAD_PROCESS_SHARED,则也能实现进程间的同步,相对而言比较麻烦。一般直接使用信号量更加方便。
这里讨论使用具名信号量以便在无血缘关系的进程之间做同步,主要涉及下面5个函数:
sem_open();//打开或者创建信号量 sem_wait();//获取信号量 sem_post();//挂出信号量 sem_close();//关闭信号量 sem_unlink();//销毁信号量
其中sem_unlink()的行为比较让人迷惑,linux内核文档描述为:
DEscriptION
sem_unlink() removes the named semaphore referred to by name. The semaphore name is removed immediately. The
semaphore is destroyed once all other processes that have the semaphore open close it.
意思是执行该函数,会立即移除信号量的id名,但是只有所有打开了该信号量的进程执行了sem_close(),才会真正销毁这个信号量。问题就出现了,id名与信号量实体可能出现分离,因为当某个进程A执行了sem_unlink,并不能确保其他进程关闭了信号量(也就是执行了sem_close),结果是信号量实体依然在内核中存在,且其他进程依然工作正常。有时候这种结果正是我们想要的,但有时候则不一定。更严重的问题是,当进程A再次打开这个信号量时(使用sem_open(),id名不变),已经无法通过id名找到之前那个信号量实体了,打开的是一个全新的信号量,虽然id名与之前一样,内容却没有关联了。
这样一来,进程A就无法与其他进程同步了。只有其他进程也执行一次sem_close和sem_unlink,并重新打开这个id名(sem_open()),才能重新连接,继续同步。因此“removes the named semaphore referred to by name”,应该理解为"立即解除name 与信号量实体的绑定关系",这样比较符合实测结果。
在使用共享内存的过程中,shmctl(id,IPC_RMID,NULL)移除共享内存,好像也有类似的问题,没有实测过。
通常当一个进程退出时,需要执行sem_unlink,也有可能程序异常退出没有执行这一步,问题比较复杂。最好是当某个进程重启了,其他相关进程也重启一下,确保所有进程打开的是同一个信号量实体,可以一定程度避免信号量和共享内存连接异常的问题。



