11.3 POSIX信号量
POSIX信号量和SystemV信号量的作用是相同的,都是用于同步进程之间及线程之间的操作,以达到无冲突地访问共享资源的目的。
在前面介绍SystemV信号量的时候也曾介绍过
Edsger Dijkstra提出了PV操作。所谓P操作,代表荷兰语中的Proberen(意思是尝试),也被称为递减操作或上锁操作。在POSIX术语中为等待(wait)。
所谓V操作代表荷兰语单次Verhogen(意思是增加),也被称为递增操作、解锁操作和发信号(signal)操作。
在POSIX术语中为挂出(post)。
POSIX信号量的作用和SystemV信号量是一样的。
q但是两者在接口上有很大的区别:
-
POSIX信号量将创建和初始化合二为一,这就解决了SystemV中可能出现竞争条件的问题。
-
POSIX信号量的修改信号量值的接口**(sem_post和sem_wait),一次只能修改一个信号量**。与之对应的SystemV信号量其本质是信号量集,其下的semop函数一次可以修改多个信号量。
-
POSIX信号量的修改信号量值的接口(sem_post和sem_wait),一次只能将信号量的值加1或减1。与之对应的SystemV信号量的semop函数,能够加上或减去一个大于1的值。
-
POSIX信号量并没有提供一个等待信号量变为0的接口,而SystemV信号量中,semop函数则提供了这样的接口。
-
POSIX信号量并没有提供UNDO操作,而SystemV信号量则提供了这样的操作。
从表面看,SystemV信号量的能力完胜POSIX信号量,事实上并非如此。
SystemV信号量有过度设计之嫌,在大部分场景下,SystemV提供的第2、3和4条特性都没有什么用处,反而徒增接口的复杂程度。
POSIX信号量提供的接口异常清晰,易于理解和使用。
POSIX信号量真正比SystemV信号量优越的地方在于,POSIX信号量性能更好。
对于SystemV信号量而言,每次操作信号量,必然会从用户态陷入内核态,可以想象当加锁和解锁操作比较频繁的时候,时间上的开销也是很可观的。
POSIX信号量则不然,只要不存在真正的两个线程争夺一把锁的情况,那么修改信号量就只是用户态的操作,并不会牵扯到内核。在竞争并不激烈的情况下,POSIX的性能要远远高于SystemV信号量。
有得必有失。
因为POSIX信号量不会每次操作都去求助内核,所以获得了性能上的提升,但却因此而失去了内核的强大后援。
System V信号量支持UNDO操作,当用户进程异常消亡之后,内核会肩负起为进程还债的责任。
但是POSIX信号量却没有这个特性。
POSIX提供了两类信号量:有名信号量和无名信号量。这两种信号量的本质都是一样的,从图11-4可以看出,最重要的sem_wait接口和sem_post接口也都是一样的。如此说来,两种信号量有何不同呢,各自应用在哪些场景呢?
图11-4 有名信号量和无名信号的接口
无名信号量,又称为基于内存的信号量,由于其没有名字,没法通过open操作直接找到对应的信号量,所以很难直接用于没有关联的两个进程之间。无名信号量多用于线程之间的同步。
有名信号量由于其有名字,多个不相干的进程可以通过名字来打开同一个信号量,从而完成同步操作,所以有名信号量的操作要方便一些,适用范围也比无名信号量更广。
下面将分别介绍这些接口。