ClarkCheung
ClarkCheung

I'm writing something about Computer Science, especially some basic knowledges.

操作系统:信号量、互斥量、管程

信号量:

在1965年,Dijkstra提出用一个整型变量来累计唤醒次数,称作信号量。一个信号量的取值可以为0或者为正值。Dijkstra建议对信号量设立两种操作:down(P操作)和up(V操作)。这两种操作均为原子操作,意为在该信号量操作结束或阻塞之前,其余进程均不允许访问该信号量。

down操作检查信号量当前的值是否>0,如果>0,将该值-1。如果=0,则进程将睡眠,并且此时down操作并未结束。up操作对信号量的值+1,如果一个或多个进程在该信号量上睡眠,无法完成先前的down操作的时候,则由系统唤醒其中的一个进程,并对信号量进行未完成的down操作。

用信号量解决生产者-消费者问题

此解决方案使用了三个信号量。一个称为full,初始值为0,用来记录已充满的缓冲槽数目,一个称为empty,初始值为N(缓冲槽的数目),记录空的缓冲槽数目,一个称为mutex,初始值为1,用来确保生产者和消费者不会同时访问缓冲区。其代码如下:

#define N 100
typedef int semaphore; //信号量
semaphore mutex = 1;
semaphore full = 0;
semaphore empty = N;

void producer(){
	int item;
	
	while(TRUE){
 item = produce_item();//生产者生产
 down(&empty);//空槽数目减少
 down(&mutex);//进入临界区
 insert_item(item);//将产品放入缓冲区
 up(&mutex);//离开临界区
 up(&full);//满槽数目增加
 
	}
}
void consumer(){
	int item;

	while(TRUE){
 down(&full);
 down(&mutex);
 item = remove_item();//从缓冲区中取出商品
 up(&mutex);
 up(&empty);
 consume_item(item);//消费商品
	}
}

互斥量(锁)

如果不需要信号量的计数功能,我们有时候可以采取信号量的简化版本,称为互斥量(mutex)(也有人称作锁)。互斥量可以处于两种状态:加锁和解锁。实际应用中,我们常使用一个整型量,0表示加锁,其他所有值表示解锁。

当一个线程需要访问临界区时,它调用mutex_lock。如果该互斥量当前是解锁的,此调用成功。反之,该线程阻塞,直到临界区中的其他线程调用mutex_unlock。

管程

通常,我们需要花费大量的精力来使用信号量,不谨慎的设计不仅不能得到应有的结果,还可能会导致死锁。为了更易于编写正确的程序,计算机科学家提出了一种高级同步原语:管程。

一个管程是一个由过程,变量及数据结构等组成的一个集合。进程可在任何需要的时候调用管程中的过程,但它们不能在管程之外声明的过程中直接访问管程内部的数据结构。管程有一个很重要的特性,即任一时刻管程内只能有一个活跃进程。这一特性使管程能有效地完成互斥。

CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论