2.14 信号量(重点)
进程通过传递信号进行协作
- 进程因为某个条件阻塞,不能继续推进
- 进程因为某个条件被唤醒,可以继续推进
可以实现信号灯作用的整数变量:信号量
信号量的三种操作
- 初始化:初始化为非负数,代表某种初始状态
- 自增semSignal(操作代号:V):该操作使信号量+1,若此时信号量仍<=0,唤醒被P操作阻塞的进程
- 自减semWait(操作代号:P):该操作使信号量-1,若此时信号量<0,则阻塞执行P该操作的进程
2.14.1 信号量分类
二元信号量:信号量值为0/1
struct binary_semaphore{
enum { zero, one } value;
queueType queue;//内置队列
};
void semwaitB(binary_semaphore s){//P操作
if(s.value == one)
s .value = zero;
else { //此时阻塞
place this process in s.queue;//当前进程加入阻塞队列
block this process;//不是忙等,不占cpu时间,等待唤醒
}
}
void semsignalB(semaphore s){//V操作
if( s.queue is empty())
s .value=one;
else {
remove a process P from s.queue;//从阻塞队列取出进程
place process P on ready list;//唤醒阻塞进程
}
}
- 计数信号量:即一般信号量,信号量取值范围更大
struct semaphore {
int count;
queueType queue;
};
void semwait ( semaphore s ){//P操作
s.count--;
if ( s.count <0 ){
place this process in s.queue;
block this process;
}
}
void semsignal ( semaphore s){//V操作
s.count++;
if ( s.count <= 0 ){
remove a process P from s.queue;
place process P on ready list;
}
}
2.14.2 信号量内部的队列
- 强信号量:进程按照FIFO移出
- 弱信号量:不规定进程移出的顺序
2.14.3 使用信号量解决互斥问题
进程不能进行P操作时需要等待另一个进程的V操作,实现互斥
/* program mutualexclusion */
const int n = / *number of processes */;
semaphore s = 1 ;//初始化
void P(int i){
while (true){
semwait(s);//P操作:semaphore=1,可以--
/*访问临界区*/;
semsignal(s);//V操作:semaphore++
/*remainder*/;
}
}
void main (){
parbegin (P( 1),P( 2), . . ., P(n) ) ;
}
2.14.4 信号量的实现
- semWait、semSignal作为原语实现
- 任意时刻仅有一个进程使用PV操作修信号量
- 可以使用硬件实现
- 可以使用前面的机器指令实现
semWait (s){P操作
while (compare_and_swap(s.flag,0,1) == 1)//指令作用:s.flag=0?s.flag=1:;循环作用:s.flag=1跳出循环
/ *do nothing */;
s.count--;
if (s.count < 0) {
place this process in s.queue;
block this process (must also set s.flag to 0);
}
s.flag = 0;
}
semSignal(s){//V操作
while (compare and swap(s.flag, 0,1) == 1)//指令作用:s.flag=0?s.flag=1:;循环作用:s.flag=1跳出循环
/* do nothing */;
s.count++;
if (s.count <= 0){
remove a process P from s.queue;
place process P on ready list;
}
s.flag = 0;
}
- s.count ≥ 0, s.count 表示执行semWait(s)操作而不被阻塞的进程数(可看作可用资源数)。这种情形信号量可支持同步与互斥。
- s.count < 0, s.count 表示阻塞在s.queue队列上的进程数。
现在信号量包含一个新的整数元素,s.flag,诚然,这可能导致一种新的忙等。然而,semWait和semSignal操作相对较短,所以涉及的忙等待量应该不大。对于单处理器系统,可以在semWait或semSignal操作的持续时间内屏蔽中断,这些操作的持续时间相对较短,意味着这种方法是合理的。