signal(c):若C队列为空,继续原进程,否则唤醒队列第一个等待者,自己进入紧急等待队列尾部。
【示例】
生产者-消费者问题(有buffer)
问题描述:(一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。
解答:
管程:buffer=MODULE;
(假设已实现一基本管程monitor,提供enter,leave,signal,wait等操作)
notfull,notempty:condition; // notfull控制缓冲区不满,notempty控制缓冲区不空;
count,in,out: integer; // count记录共有几件物品,in记录第一个空缓冲区,out记录第一个不空的缓冲区
buf:array [0..k-1] of item_type;
define deposit,fetch;
use monitor.enter,monitor.leave,monitor.wait,monitor.signal;
procedure deposit(item);
{
if(count=k) monitor.wait(notfull);
buf[in]=item;
in:=(in+1) mod k;
count++;
monitor.signal(notempty);
}
procedure fetch:Item_type;
{
if(count=0) monitor.wait(notempty);
item=buf[out];
in:=(in+1) mod k;
count--;
monitor.signal(notfull);
return(item);
}
{
count=0;
in=0;
out=0;
}
进程:producer,consumer;
producer(生产者进程):
Item_Type item;
{
while (true)
{
produce(&item);
buffer.enter();
buffer.deposit(item);
buffer.leave();
}
}
consumer(消费者进程):
Item_Type item;
{
while (true)
{
buffer.enter();
item=buffer.fetch();
buffer.leave();
consume(&item);
}
}
【附】有关wait和signal的语言表示
信号量结构使用C语言表示如下:
typedef struct {
int value;//记录了这个信号量的值
struct process *list;//储存正在等待这个信号量的进程
} semaphore;
wait()信号量部分代码如下:
wait(semaphore *S) {
S->value--;
if(S->value < 0) {
add this process to S->list;
block();
}
}
signal()信号量部分代码如下:
signal(semaphore *S) {
S->value++;
if(S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
一、The Bounded-Buffer Problem:
full初始化为0,empty初始化为n,mutex为1
do{
wait(full);
wait(mutex);
...
//remove an item from buffer to nextc
...
signal(mutex);
signal(empty);
...
//consume the item in nextc
...
} while(TRUE);
二、The Readers-Writers Problem:
wrt初始化为1,readcount初始化为0,mutex为1
写者操作:
do{
wait(wrt);
...
//writing is performed
...
signal(wrt);
} while(TRUE);
读者操作:
do{
wait(mutex);//确保与signal(mutex)之间的操作不会被其他读者打断
readcount++;
if(readcount == 1)
wait(wrt);
signal(mutex);
...
//reading is performed
...
wait(mutex);
readcount--;
if(readcount == 0)
signal(wrt);
signal(mutex);
} while(TRUE);
三、The Dining-Philosophers Problem:
所有的chopstick[5]全部初始化为1
do{
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
...
//eating
...
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
...
//thinking
...
} while(TRUE);
但是这个解决方案的最大问题在于它会出现死锁。所以我认为应该增加一个信号量mutex,并初始化为1:
do{
wait(mutex);
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
signal(mutex);
...
//eating
...
wait(mutex);
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
signal(mutex);
...
//thinking
...
} while(TRUE);
这样由于确保了一位哲学家在拿起两只筷子的时间内其他哲学家不可以拿起任何一支筷子,从而破坏了死锁出现需要的四个特征中的Hold And Wait特征,从而避免了死锁的发生。