利用记录型信号量机制来解决进程同步的三个经典问题
进程同步问题中有三个经典问题:生产者—消费者问题;哲学家进餐问题;读者—写者问题
首先是生产者—消费者问题:
详情见:操作系统经典问题——消费者生产者问题_操作系统生产者消费者问题_用编程写诗的博客-CSDN博客
首先第一点什么是生产者——消费者问题:
系统中有一组生产者进程和一组消费者进程。生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用,那么他们之间具有这样一层关系。
利用记录型信号量解决生产者—消费者问题:假定在生产者和消费者之间的公用缓存池中具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用。利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。
初始化:semaphore mutex=1,empty=n,full=0;初始状态下互斥信号量是1空缓冲区也是有n个的非空缓冲区是0个。
生产者生产:
producer (){
while(1)
{ 生产一个产品;
P(empty);//判断是否为空
P(mutex);//判断是否可以进入临界区寻找资源
把产品放入缓冲区;
V(mutex);//释放临界区的资源
V(full); } //非缓冲区有多少产品}
P(mutex)和V(mutex)实现进程的互斥访问,P(empty)实现让缓冲区没满作为生产者生产的前操作,即当empty=0时即无空闲缓冲区数量时,让消费者消费作为生产者生产的前操作。
V(full)实现让缓冲区不空作为消费者消费的前操作,即当full=0时即缓冲区全为空时,让生产者生产作为消费者消费的前操作。
消费者消费:
consumer(){
while(1)
{ p(full);//判断非缓冲区是否还有产品
p(mutex);//判断是否可以进入临界区寻找资源
从缓冲区中拿出产品消费
v(mutex);//释放临界区的资源
v(empty);//为空缓冲区增加一个位置}
P(mutex)和V(mutex)实现进程的互斥访问,V(empty)实现让缓冲区没满作为生产者生产的前操作,即当empty=0时即无空闲缓冲区数量时,让消费者消费作为生产者生产的前操作。
P(full)实现让缓冲区不空作为消费者消费的前操作,即当full=0时即缓冲区全为空时,让生产者生产作为消费者消费的前操作。
在生产者—消费者问题当中empty和full的p,v操作需要成对出现,否则就会出现死锁。
哲学家进餐和读者—写者问题详见:操作系统经典同步问题——读者-写者问题和哲学家进餐问题_用编程写诗的博客-CSDN博客
接着是哲学家进餐问题:哲学家进餐问题就是指的是五个哲学家围着一个圆桌进行进餐。但是只有5只筷子,平时哲学家进行思考饥饿的时候试图用左右最靠近他的筷子。只有拿到两只筷子才能进餐完毕,放下筷子进行思考。
mutex[5] = {1,1,1,1,1}; //初始化信号量
philosopher(){
while(1) {
P(mutex[i]); //拿左边的筷子
P(mutex[(i+1)%5]);//拿右边的筷子
进餐...
V(mutex[i]);//放回左边的筷子
V(mutex[(i+1)%5]);//放回右边的筷子
}
但是当所有的哲学家都拿了他左边的筷子的时候,那么就无筷子可拿了。这时候就会出现死锁的现象。关于这种情况我们有三种解决方法。
(1)最多让4个哲学家同时去拿左边的筷子那么这样肯定会有一个哲学家可以用餐用完餐之后释放筷子其他人也可以正常使用了。
(2)哲学家必须同时可以拿到左右两只筷子时才允许他拿起筷子进餐
(3)给哲学家标记序号,奇数号哲学家拿左边筷子再拿右边筷子而偶数号哲学家则相反。那么按照规定1,2号哲学家竞争1号筷子,3,4号哲学家竞争3号筷子,即所有哲学家都先竞争奇数号筷子再竞争偶数号筷子最终肯定有一个哲学家可以拿到两只筷子进餐。
最后是读者—写者问题:
在读者—写者问题当中,只读该文件的进程称为读者进程,其他进程称为写者进程。允许多个读者同时读一个进程但是不允许多个写者进程同时写或者一个写者写其他读者读。
我们可以看到写者是和其他进程都是互斥的所以我们采用一个互斥量Wmutex就可以解决问题了。
Writer(){
while(1){
P(Wmutex)
进行写操作
V(Wmutex)
}
}
对于读者问题我们发现在这个问题当中读者是和读者同步的但是他是跟写者互斥的。我们在这种情况下设置一个用来记录读者数量的readcount的变量根据读者的数量来进行判读如果读者的数量>0那么这时只可以进行读者的访问写者的访问时不可以的每一次进行对写者的操作时都需要我们先判断readcount的数值。我们同样也为读者设置一个互斥信号量rmutex
Reader(){
while(1){
p(rmutex) //各读进程互斥访问readcount
if(readcount==0) p(Wmutex) //当前没有读者就可以进行写者的操作
readcount++ //读者申请的话需要数量加一
v(rmutex)
读文件... //上面这一部分使得多个读者能够同时访问接下来读进程结束要出来
P(rmutex);//各读进程互斥访问raeadcount
readcount--;//每当一个读进程完成读操作,读者数量-1
if(readcount==0) //当前没有读者就可以进行写者的操作
V(wmutex);//当没有读者,读操作结束后,写进程解锁
V(rmutex);
}
}