第5章 Posix信号量
5.1 概述
Posix信号量分为两种:
1. 有名信号量:使用Posix IPC名字标识。
2. 内存信号量:存放在共享内存区中。
Posix信号量不必在内核中维护(System V信号量由内核维护),由可能为路径名的名字来标识。
5.2 基本操作
三种基本操作:
1. 创建(create):指定初始值。
2. 等待(wait):如果值小于等于0则阻塞,否则将其减一,又称P操作。
3. 挂出(post):将信号量的值加1,加后如果值大于0,则唤醒一个阻塞在等待上的线程,又称V操作。
二值信号量可用于互斥,就像互斥锁一样。但互斥锁必须由锁住它的线程解锁,信号量的挂出却不必由执行过等待的同一线程执行。
信号量的wait和post与条件变量的wait和signal类似,区别是:因为永久的改变了信号量的值,信号量的操作总被记住(会影响到后续的操作);条件变量的signal如果没有线程在等待,该信号将丢失(对后续操作没有影响)。
互斥锁是为上锁而优化的,条件变量是为等待优化的,信号量既可以上锁也可以等待,因此开销更大。
5.3 Posix信号量操作
有名信号量: | 内存信号量: |
sem_open | sem_init:需要指定是否共享 |
sem_wait:原子的“测试并减1”操作 | |
sem_trywait | |
sem_post:同步技巧中唯一能在信号处理函数内安全调用的操作 | |
sem_getvalue | |
sem_close | sem_destroy |
sem_unlink |
|
即使当前没有进程打开信号量,它的值仍然保持,因此Posix有名信号量至少是随内核持续的。
在父进程中打开的任何信号量,fork后在子进程中仍打开。
5.4 生产者-消费者问题
这里的解决方案需要一个二值信号量、两个计数信号量:
1. mutex:二值信号量用于提供buffer的互斥访问。
2. nempty:初始为n的信号量,空槽位数。
3. nstored:初始为0,已填写的槽位数。
Posix允许sem_wait检测死锁并返回EDEADLK错误,但很多实现都没有提供这一功能。
多个缓冲区问题是生产者-消费者问题的变种。
5.5 内存信号量
彼此无亲缘关系的进程间需使用信号量时,一般用有名信号量。如果不需要使用关联名字时,可改用内存信号量。
内存信号量需要放在共享内存区中,并由sem_init函数初始化为shared状态才能被不同进程使用,这种情况下它的持续性与共享内存区相同。
5.6 信号量限制
两个限制:
1. SEM_NSEMS_MAX:一个进程可同时打开着的最大信号量数。
2. SEM_VALUE_MAX:一个信号量的最大值。