1. 信号量应用
1.1 实现进程互斥
利用互斥信号量mutex实现,互斥信号量初始值为1.
在临界区前后分别加上wait(mutex)和signal(mutex)即可。但一定要注意必须成对出现,否则将造成混乱。
实际上也可以用Swait(mutex,1,1)和Ssignal(mutex,1,1)实现。
1.2 实现前趋关系
简单得很。比如
S1是s2和s3的前趋,s1没有前趋,s2是s4和s5的前趋,s4和s5和s3是s6的前趋。
Mn_n分别表示连接关系,初始值定为0.
分别在sn代码前后加上signal(mn_n)和wait(mn_n).
而没有前趋的s1前当然就不用加wait(),因为它的执行不需要其他前提。而需要前提的sn前均要加上相应的前趋关系wait(mn_n);
2. 生产者消费者问题
2.1 利用记录型信号量解决
用mutex=1实现对缓冲池的互斥使用
用empty=n和full=0分别表示缓冲池中空的和满的缓冲区数量。In和out分别控制buffer角标。实现缓冲区的循环使用。初始值均为0。
生成者循环执行:
生产一个产品
Wait(empty)
Wait(mutex)
Buffer(in)=nextp; //存入产品
In=(in+1)mod n
Signal(mutex);
Signal(empty);
消费者循环执行:
Wait(full);
Wait(mutex);
Nextc=buffer(out);取走产品
Out=(out+1)mod n;
Signal(mutex);
Signal(empty);
消费产品;
2.2 利用AND信号量
直接用Swait(empty,mutex)和Ssignal(full,mutex)代替原来的那两个步骤。
3. 哲学家进餐问题
3.1 记录型信号量
由于他们需要占用的资源分别是左右两边的筷子,用c[i] i=0~4来表示每支筷子,那么第i个哲学家需要的筷子分别是c[i]和c[(i+1)mod 5]。
所以用筷子做为信号量来控制:对于第i位哲学家
Wait(c[i]);
Wait(c[(i+1)mod 5])
Eat;
signal(c[i]);
signal(c[(i+1)mod 5])
Think;
可以看出过程就是在他们吃的时候,总是先拿左边的筷子,再拿右边的筷子,之后再先放左边的筷子,再放右边的。那么就有可能出现一种死锁的情况。如果所有哲学家同时饥饿,同时拿起左边的筷子,而永远拿不到右边的筷子了,大家都会处在无限的等待里。解决办法:
1.最多只允许四位拿起左边的筷子。
2.只有左右两边都有筷子时,才允许他拿起筷子。(AND信号量采用的方法)
3.规定所有哲学家都先竞争奇数号筷子,再竞争偶数号筷子,最后总有一位能顺利进餐。
3.2 AND信号量解决
直接用Swait(c[i],c[(i+1)mod 5)和Ssignal(c[i],c[(i+1)mod 5)代替原来的那两个步骤。表示获得了两个临界资源后方能进餐。
4. 读者写者问题
实际上是要保证一个写进程要和其他所有进程互斥使用共享对象。
4.1 记录型信号量解决
原理:用readcount=0表示正在使用共享对象的读进程数。用wmutex=1实现写进程与其他进程的互斥使用。同时因为readcount也是共享数据,用rmutex=1实现它的互斥访问。
读进程:
Wait(rmutex)
If(readcount=0)
Wait(wmutex)
Readcount++;
Signal(rmutex);
Read();
Wait(rmutex);
Readcount--;
If(readcount=0)
Signal(wmutex);
Wait(rmutex);
写进程:
Wait(wmutex)
Wright();
Signal(wmutex);
4.2 信号量集解决
问题稍有变化:增加了一个限制,即最多允许RN个读进程同时读。
写进程:
Swait(L,1,1);//控制读进程个数,L初值为RN
Swait(wx,1,0);//控制与写进程的互斥,只有当wx为1时才能读,但是读进程并不消耗mx。
Read();
Ssignal(L,1);//释放L信号量
写进程:
Swait(wx,1,1;L,RN,0);//表示既没有任何进程在写,也没有任何进程在读。要求有L的最小值为RN,即是说明没有进程在读。
Wright();
Ssignal(wx,1);