信号量机制是一种功能较强的机制,可用来解决互斥和同步的问题,它只能被两个标准的原语访问。
P – 申请/占有空间 wait(s)
V – 释放资源 signal(s)
整型信号量
wait(s){
while(s<=0);
s = s - 1; //P操作 占用一个资源
}
signal(s){
s = s + 1; // V操作 释放一个资源
}
利用信号量实现同步
同步:要让并发的进程按要求有序的推进
//前V(s)后P(s)
//如下,执行y时需要x的计算结果,因此需要先执行x再执行y
semaphore s = 0;
P1(){
...
x;
//释放s=1
V(s);
}
P2(){
...
//经过v(s)后,可申请到s;否则申请不到s
P(s);
y;
}
利用信号量实现互斥
互斥:某些临界资源,只可以互斥访问
semaphore s = 1;
P1(){
...
P(s); //s=0
访问临界资源; //临界区
V(s);
}
P2(){
...
P(s);
访问临界资源;
V(s);
}
在pv操作的同步和互斥的关系中,若某一种行为需要某种资源,“P一下”
这种资源;而当需要释放某种资源时,我们就“V一下”
这种资源
PV总是成对出现
;当出现互斥关系时,将临界区的代码夹在中间,一气呵成
生产者消费者问题
问题描述: 一组生产者进程和一组消费者进程共享大小为n的缓冲区,只有缓冲区没满时,生产者才能把信息放入缓冲区;只有缓冲区不为空时,消费者才能从中取出信息。同时只允许一个生产者或消费者同时在缓冲区操作。
分析: 互斥访问;只有生产者生产后,消费者才能消费。
semaphore mutex = 1; //临界互斥信号量
semaphore empty = n; //空闲缓冲区
semaphore full = 0; //初始缓冲区为空
//生产者进程
producer(){
while(1){
produce data; //生产
P(empty);
P(mutex);
add data to buffer; //放入缓冲区
V(mutex);
V(full);
}
}
//消费者进程
consumer(){
while(1){
P(full);
P(mutex);
remove data to buffer;
V(mutex);
V(empty);
}
}
读者-写者问题
约束条件:
- 允许多个读者在同时对文件执行读操作(读进程可同时访问)
- 只允许一个写者往文件里写信息
- 任一写者在完成写操作前,不允许其他读者或写者工作(写进程和读写进程均互斥)
- 写者执行操作前将已有的读者和写者推出
int count = 0; //计数器
semaphore rw = 1;
writer(){
while(1){
P(rw);
writing;
V(rw);
}
}
reader(){
while(1){
/****************/
P(mutex);
if(count == 0){ //判断是不是第一个读者
P(rw);
count++;
V(mutex);
/****************/
reading;
/****************/
P(mutex);
count--;
if(count == 0) //判断是不是最后一个读者
V(rw);
V(mutex);
/****************/
}
}
}
读进程和读进程可同时访问,第二个以及后续读者进入时不需要再申请rw,只需要 count++ 进行计数;
当读完后读者退出执行count- -,当count=0时,最后一个读者读完再释放rw
用count判断是否是第一个/最后一个
读者(读进程
)
哲学家进餐问题
问题描述: 有五个哲学家共用一张圆桌,在圆桌上有五个碗和五支筷子。平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件:
- 只有拿到两只筷子时,哲学家才能吃饭;
- 如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子;
- 任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子(易产生死锁)。
semaphore chopstick[5] = {1,1,1,1,1};
semaphore mutex = 1;
Pi(){
while(1){
P(mutex); //对拿筷子的过程用互斥锁
P(chopstick[i]); //取左边筷子
P(chopstick[(i+1)%5]); //取右边筷子
V(mutex);
eat;
V(chopstick[i]); //放下左筷子
V(chopstick[(i+1)%5]);
think;
}
}
在哲学家拿起左边筷子的过程中,右边的筷子不能被其他的哲学家拿走,因此需要使用互斥锁,防止死锁
吸烟者问题
问题描述: 有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽调一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一、二、三个分别拥有烟草、纸和胶水。供应者进程无限提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供应者就放另外两种材料在桌子上,这个过程一直重复,让三个抽烟者轮流地抽烟。
分析: 供应者和三个抽烟者是同步
关系;三个抽烟者对抽烟是互斥
关系
int num = 0; //存储随机数,实现轮流抽烟
semaphore offer1 = 0; //1 2 3分别表示需要三种原材料
semaphore offer2 = 0;
semaphore offer3 = 0;
semaphore finish = 0; //表示抽烟是否完成
//供应者进程
process P1(){
while(1){
num++;
num = num % 3; //轮流
if(num == 0)
V(offer1);
else if(num == 1)
V(offer2);
else V(offer3);
P(finish); //申请finish,告诉吸烟者可以拿材料了
}
}
process P2(){
while(1){
P(offer3);
抽烟;
V(finish); //释放finish,告诉供应者进程完成了
}
}
process P3(){
P(offer2);
抽烟;
V(finish);
}
process P4(){
P(offer1);
抽烟;
V(finish);
}