信号量
信号量和PV操作
Struct semaphore{
int value; //信号量值
pointer_PCB queue; //信号量队列指针
}
PV操作
苹果橘子问题
生成者消费者问题
这样定义四个信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。
生成者进程:
while(TRUE){
生产一个产品;
P(empty);
P(mutex1);
产品送往buffer(in);
in=(in+1)mod n;
V(mutex1);
V(full);
}
消费者进程:
while(TRUE){
P(full)
P(mutex2);
从buffer(out)中取出产品;
out=(out+1)mod n;
V(mutex2);
V(empty);
消费该产品;
}
!!!两个P不能交换:不能先执行 P(mutex)在执行P(empty),如果这样做了,生成者对缓冲区加锁后,执行P(empty)操作,发现empty=0.生成者只能阻塞;但因为mutex已经为0,所以消费者不能进入临界区。
三个进程合作打印文件
信号量:full1,full2:缓冲区是否有记录可供处理,初值0。
empty1,empty2:缓冲区是否有空位,初值1.
mutex1,mutex2互斥信号量:表示缓冲区1,2的访问控制,初值1。
semaphore full1=0;
semaphore full2=0;
semaphore empty1=1;
semaphore empty2=1;
semaphore mutex1=1
semaphore mutex2=1;
PA(){
while(1){
从磁盘读一个记录;
P(empty1);
p(mutex1);
将记录放入缓冲区1;
V(mutex1);
V(full1);
}
}
PB(){
while(1){
P(full1);
p(mutex1);
从缓冲区读取一个记录;
V(mutex1);
V(empty1)
P(empty2);
P(mutex2);
将记录放入缓冲区2;
V(mutex2);
V(full2);
}
}
PC(){
while(1){
P(full2);
P(mutex2);
从缓冲区2读取一个记录;
V(empty);
V(mutex2);
打印记录;
}
}
课后习题
总结:找出 互斥资源 和 同步关系。设置信号量。
首先对于AB两侧,桥是一个互斥资源,同一侧每个人上桥是同步关系,AB两侧的人在抢到这互斥资源后只有最后一个人通过了独木桥才释放。
AND型信号量集
有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
!!!筷子是资源
repeat
wait(chopstick[i]
wait(chopstick[(i+1)mod5]
eat;
signal(chopstick[i])
signal(chopstick[(i+1)mod5]
仔细分析就会发现若五位哲学家每个人都同时饥饿而拿起了左边的筷子,这使五个信号量 chopstick 均为 0,当他们试图去拿起右边的筷子时,都将因无筷子而无限期地等待下去,即可能会引起死锁。
方法一:至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
方法二:仅当哲学家的左右手筷子都拿起时才允许进餐。
方法三:规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。
方法二:AND型信号量和信号量集机制。
AND型信号量集是指同时需要多个资源且每种占用一个资源时的信号量操作。当一段处理代码需要同时获取两个或多个临界资源时,就可能出现由于各进程分别获得部分临界资源并等待其余的临界资源的局面。各进程都会“各不相让”,从而出现死锁。
解决这个问题的一个基本思路是:在一个原语中申请整段代码需要的多个临界资源,要么全部分配给它,要么一个都不分配给它。这就是AND型信号量集的基本思想。
AND型信号量集P原语为Swait(Simultaneous Wait),V原语为Ssignal(Simultaneous Signal)。
S1到Sn都表示所需资源,资源数都大于1,可以对每个资源进行申请,分配好资源之后跳出循环,wait操作结束。如果其中某个资源Si得不到满足,会执行else中的内容:把进程放进Si关联的阻塞队列中,然后程序计数器把指针移向wait操作开始。(wait操作是原语,遵循要执行都执行,执行不了就从头重新执行)
signal操作表示的是释放资源,把S1到Sn全部资源释放,并且把S1到Sn关联的阻塞队列全部置空,阻塞队列中的进程直接调度到就绪队列中。
AND型信号量满足了
“多种资源,数量为1”的使用情景,但是实际上还会有多种资源数量不固定的情景,AND型信号量显然处理不了这种情况的进程调度。为了解决多资源多数量的情况,就出现了信号量集。
信号量集
一般“信号量集”是指同时需要多种资源、每种占用的数目不同、且可分配的资源还存在一个临界值时的信号量处理。由于—次需要n个某类临界资源,因此如果通过n次wait操作申请这n个临界资源,操作效率很低,并可能出现死锁。
—般信号量集的基本思路就是在AND型信号量集的基础上进行扩充,在一次原语操作中完成所有的资源申请。进程对信号量Si的测试值为ti(表示信号量的判断条件,要求Si>ti即当资源数量低于ti时,便不予分配),占用值为di(表示资源的申请量,即Si=Si—di)。对应的P、V原语格式为:
一般“信号量集”可以用于各种情况的资源分配和释放。下面是几种特殊的情况:
1)Swait(S,d,d)表示每次申请d个资源,当资源数量少于d个时,便不予分配。2)Swait(S,1,1)表示互斥信号量。
3)Swait(S,1,0)可作为一个可控开关(当S≥1时,允许多个进程进入临界区;当S=0时禁止任何进程进入临界区)。