信号量详解

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操作的持续时间内屏蔽中断,这些操作的持续时间相对较短,意味着这种方法是合理的。

猜你喜欢

转载自blog.csdn.net/qq_44722674/article/details/111507920