POSIX信号量

提起信号量,大多数人首先想到SystemV 信号量,熟悉POSIX信号量的人则相对少一点,下面就对POSIX信号量做一个简单介绍,但在此之前,我们先简单回顾一下SystemV 信号量,以便比较它们的异同。SystemV 信号量是内核对象,由内核统一管理,用户程序通过semget(2)向内核提出申请,内核根据需要创建新的信号量或者关联已存在的信号量,每组信号量都有唯一的ID标识,可以被多个进程共享。PV操作通过调用semop(2)或者semtimedop(2)来进行。因为SystemV 信号量是内核对象,所以它的存续不依赖于进程,而是由内核管理,即使进程退出也仍然存在,要删除信号量必须显式地调用semctl(2)。有两条命令用来管理System V 信号量:ipcs(1)ipcrm(1)ipcs -s 用于查看,ipcrm -s 用于删除。

POSIX信号量与SystemV 不太一样,它分为两类:无名信号量(unnamed semaphore) 和 有名信号量(named semaphore)

有名信号量与System V 信号量类似,它也是由内核统一管理的,但不是用ID作标识,而是用名字作标识,有名信号量的名字有点像文件名,必须是以”/”开头的字符串,但不能包含字符”.”。用户程序通过调用sem_open(3)创建或打开有名信号量。有名信号量的存续也是内核决定的,与进程是否退出没有关系,必须显式调用sem_unlink(3)才能删除。在Linux系统上,有名信号量跟共享内存一样,会在/dev/shm 目录下产生文件,管理有名信号量通过这些文件进行,查看的命令如下:

删除的命令如下:
$ rm /dev/shm/sem.mysem

无名信号量是基于user memory的,通过sem_init(3)创建,调用参数中需要指定放置信号量的内存地址,这个地址可以是私有内存,也可以是共享内存。如果要在多个进程之间共享无名信号量的话,就必须使用共享内存。在实践中,无名信号量一般用于线程之间、或者父子进程之间,否则编程有点麻烦:因为要事先约定好无名信号量的地址才行。由于无名信号量建立在user memory上,它的存续与内存的存续直接相关,如果无名信号量位于进程的私有内存(比如进程的全局变量),那么当该进程终止时无名信号量也会消失;如果无名信号量是在共享内存区中,那么只要该共享内存区还存在,该信号量就存在,而与进程是否中止没有关系。
注:好像没有命令用来查看或管理无名信号量。

POSIX信号量的PV操作通过调用sem_wait(3)和sem_post(3)进行,对无名信号量和有名信号量都一样。

POSIX信号量的API是库函数,而SystemV信号量的API是系统调用(system calls)。如果你用strace(1)跟踪一下,会看到SystemV信号量使用的系统调用是semget(2)/semctl(2)/semop(2)等,而POSIX信号量使用的系统调用是futex(2)。使用POSIX信号量的程序需要链接librt.xxx库,编译时使用-lrt参数。