【生产者与消费者的同步关系】
生产者:
当有界缓冲区中无空位置时,要等待;
向有界缓冲区放入物品后,要发消息。
消费者:
当有界缓冲区中无物品时,要等待;
从有界缓冲区取出物品后,要发消息。
【解答步骤】
【程序描述】
//设置信号量
main()
{
semaphore mutex = 1; //互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n; //同步信号量,空闲缓冲区的数量
semaphore full = 0; //同步信号量,产品数量/非空缓冲区的数量
cobegin
p1();p2(); //p为生产者
c1();c2(); //c为消费者
coend
}
pi()
{
while(1) //生产未完成
{
生产一个产品;
P(empty); //消耗一个空闲缓冲区
P(mutex); //实现互斥是保证在同一进程中进行一对PV操作
把产品送到有界缓冲区;
V(mutex);
V(full); //增加一个产品,实现同步!
}
}
ci()
{
while(1) //生产未完成
{
生产一个产品;
P(full); //消耗一个产品,实现与生产者的同步!
P(mutex);
从有界缓冲区取出一个产品;
V(mutex);
V(empty); //增加一个空闲缓冲区
消费一个产品;
}
}
提醒:
①实现互斥的P操作一定要在实现同步的P操作之后(否则会造成死锁!)
②两个V操作不会导致进程阻塞,故可以交换!
【问题描述】
一个数据对象可以为多个并发进程所共享。其中有的进程可能只需要读共享对象的内容,而其他进程可能要更新共享对象(即读和写)。
读读不互斥;读写、写写互斥。
仅当无读者等待时,才允许写者执行,即读者优先
【程序描述】
//第一读者-写者问题
main()
{
semaphore wrt = 1; //互斥信号量,写者与其他读者/写者互斥的访问
semaphore mutex = 1; //互斥信号量,互斥访问临界资源readcount
int readcount = 0; //记录目前的读者数
cobegin
Reader1();
Reader2();
...
Writer1();
Writer2();
coend
}
Writer()
{
while(1)
{
P(wrt); //互斥语句,或写成wait(wrt);
写者执行;
V(wrt); //互斥语句,或写成signal(wrt);
}
}
Reader()
{
while(1)
{
P(mutex); //PV保护临界资源
readcount++; //读者进后读者数+1
if(readcount == 1)
P(wrt); //第一个读者判断有无写者,有就进不了,没有就可以进并且阻塞写者
V(mutex);
读者执行;
P(mutex);
readcount--;
if(readcount == 0)
V(wrt); //当没有读者,则写者可进
V(mutex);
}
}
在读者与写者同时申请资源的时候,写者优先
(插后面未运行的读者的队而不是正在运行的读者的队)
【程序描述】
//第二读者-写者问题
main()
{
semaphore wrt = 1; //互斥信号量,写者与其他读者/写者互斥的访问
semaphore mutex = 1; //互斥信号量,互斥访问临界资源readcount
semaphore w = 1; //用于实现"写"优先
int readcount = 0; //记录目前的读者数
cobegin
Writer1();
Writer2();
...
Reader1();
Reader2();
coend
}
Writer()
{
while(1)
{
P(w); //申请读取权限
P(wrt);
写者执行;
V(wrt);
V(w); //释放读取权限
}
}
Reader()
{
whlie(1)
{
P(w); //申请不到权限则一直等待
P(mutex); //多个读者互斥
if(readcount == 1) //第一个读者判断有无写者,有就进不了,没有就可以进并且阻塞写者
P(wrt);
readcount++;
V(mutex); //释放互斥信号量
V(w);
读者执行;
P(mutex);
readcount--;
if(readcount == 0)
V(wrt);
V(mutex);
}
}
【程序描述】
semaphore chopstick[5] = {1,1,1,1,1} //初始化为1
Pi() //第i位哲学家结构
{
do {
wait(chopstick[i]); //取左筷子i
wait(chopstick[(i + 1) % 5]); //因为是圆桌,若i=0则i的右手边为第5根筷子
…
吃饭;
…
signal(chopstick[i]);
signal(chopstick[(i + 1) % 5]);
…
思考;
…
} while (1);
}
【问题】
【解决】
semaphore chopstick[5] = {1,1,1,1,1}; //初始化为1
semaphore count = 4;
Pi() //第i位哲学家结构
{
do {
wait(count); //判断是否超过四个人进餐
wait(chopstick[i]); //取左筷子i
wait(chopstick[(i + 1) % 5]); //因为是圆桌,若i=0则i的右手边为第5根筷子
…
吃饭;
…
signal(chopstick[i]);
signal(chopstick[(i + 1) % 5]);
signal(count); //用餐完毕释放资源
…
思考;
…
} while (1);
}
semaphore chopstick[5] = {1,1,1,1,1} //初始化为1
Pi() //第i位哲学家结构
{
do {
if(i%2 == 1) //奇数号
{
wait(chopstick[i]); //取左筷子i
wait(chopstick[(i + 1) % 5]); //因为是圆桌,若i=0则i的右手边为第5根筷子
}
else //偶数号
{
wait(chopstick[i+1]%5); //取右
wait(chopstick[i]); //取左
}
…
吃饭;
…
signal(chopstick[i]);
signal(chopstick[(i + 1) % 5]);
…
思考;
…
} while (1);
}
桌上有一个盘子,可以放一个水果;
父亲总是放苹果到盘子中;
母亲总是放香蕉到盘子中。
一个儿子专等吃盘中的香蕉;
而一个女儿专等吃盘中的苹果。
父母只放水果不吃,儿女只吃水果不放。
实现父亲,母亲,儿子,女儿的进程同步。
用PV操作实现下述问题的解
某寺庙,有小,老和尚若干,有一个水缸,有小和尚打水入缸供老和尚取水饮用。
水缸可以放10桶水。水桶总数为3个。
每次入、取缸水只能是1桶,且不可以同时进行。
小和尚从一个井里面打水。水井狭窄,每次只能容纳一个桶取水。
试用信号量和P,V操作给出小和尚打水入缸和老和尚从缸里取水的算法描述
一个快餐厅有4类职员:
(1)领班:接受顾客点菜,出菜单;
(2)厨师:根据菜单,准备顾客的饭菜;
(3)打包工:将做好的饭菜打包;
(4)出纳员:收款并提交食品。
每个职员可被看作一个进程,试用一种同步机制写出能让四类职员正确并发运行的程序。
在公共汽车上,司机和售票员的活动分别是:
司机的活动:启动车辆,正常行车,到站停车。
售票员的活动:上下乘客,关车门,售票,开车门,上下乘客。
在汽车不停的到站,停站,行驶过程中,这两个活动有什么同步关系?用信号量和P,V操作实现它们的同步。
假设有一个作业由四个进程组成,这四个进程在运行时必须按如图所示的次序依次执行,试用P,V原语表达四个进程的同步关系。
用P,V操作实现下述问题的解:
观察者和报告者是两个并发执行的进程,观察者不断观察并对通过的卡车计数,报告者定时的将观察者的计数值打印,打印完毕,将计数值清零。
假定阅览室最多可同时容纳100个人阅读,读者进入时,必须在阅览室门口的一个登记表上登记,内容包括姓名、座号等,离开时要撤掉登记内容。
用P、V操作描述读者进程的同步算法