【操作系统】信号量解决经典同步问题


信号量机制是Dijkstra提出的一种卓有成效的进程同步工具。信号量有整形信号量、记录型信号量、AND型信号量等,这里主要介绍我们常见的记录型信号量。

1. 基本结构

typedef struct {
   
	int value;  //信号量值
	struct process_cntrol_block *list;  //阻塞队列
}semaphore;

在应用信号量的时候,信号量的值往往是临界资源的数量。当临界资源数量不足时,新的进程就阻塞,并插入到信号量阻塞队列中。

2. P,V操作

wait(S)和signal(S)操作是信号量机制的基本操作(通常称作P,V操作),定义如下:

wait(semaphore *S) {
   
	S->value--;  //信号量的值减一
	if(S->value < 0) block(S->list);  //如果信号量的值小于零,进程阻塞

signal(semaphore *S) {
   
	S->value++;  //信号量的值加一
	if(S->value <= 0) wakeup(S->list);  //唤醒
}

在实现进程同步时,一般先将S->value的初值设定为临界资源的初始数量,一旦进程要请求一个临界资源,先对代表此进程的信号量执行P操作,也就意味着资源数减一,当该进程运行完毕时,执行V操作,意味着资源数加一。值得注意的是,如果当前资源数量为0,再有进程想请求临界资源,就会在执行P操作时进入阻塞队列,信号量值变为-1,此后执行P操作的进程也都会被阻塞,信号量的绝对值为阻塞的进程数目。

3. 信号量的应用

3.1 信号量实现进程互斥

有了P,V操作,我们就能很简单的实现进程互斥。方法是:设mutex为互斥信号量,初值为1。在需要互斥的临界区前后分别使用P,V操作即可,示意代码如下:

semaphore mutex = 1;  //一般初值为1的信号量用来实现互斥
P_A() {
     //进程A
	while(1) {
   
		P(mutex);
		临界区;
		V(mutex);
		剩余区;
	}
}
P_B() {
     //进程B
	while(1) {
   
		P(mutex);
		临界区;
		V(mutex);
		剩余区;
	}
}

在互斥问题中,我们可以把P操作理解成“上锁”,把V操作理解成“解锁”,当P_A和P_B两个进程并发执行时,无论哪一个进程先执行到了P操作,都会接下来执行P操作的进程阻塞,直到前一个进程执行到了V操作为止,这样就实现了临界区的互斥。

3.2 信号量实现前驱关系

思路如下:为每一组想要实现前后关系的进程,都分别定义一个信号量,初值设为0,把你想要先执行的进程后面加一个V操作,想要后执行的进程前面加一个P操作。这样一来,你想要后执行的进程如果先执行了,就会因为执行了其前面的P操作而阻塞,直到你想要先执行的进程执行完了,执行V操作后,才能解除阻塞继续执行。以上就是用信号量实现前驱关系的过程。
假如我们要实现四个语句S1,S2,S3,S4需要按照一定的顺序同步执行,比如S1执行完S2,S3才能执行,S2,S3执行完了S4才能执行,代码如下:

p1() {
   S1; V(a); V(b);}
p2() {
   P(a); S2; V(c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值