1.某进程中有3个并发执行的线程thread1、thread2、thread3,其伪代码如下所示。请添加必要的信号量和P、V操作,要求确保互斥访问临界资源
//复数的结构类型定义
typedef struct
{
float a;
float b;
}cnum;
cnum x,y,z; //全局变量
//计算两个复数之和
cnum add( cnum p,cnum q)
{
cnum s;
s.a=p.a+q.a;
s.b=p.b+q.b;
return s;
}
thread1
{
cnum w;
w=add(x,y);
...
}
thread2
{
cnum w;
w=add(y,z);
...
}
thread3
{
cnum w;
w.a=1;
w.b=2;
z=add(z,w);
y=add(y,w);
...
}
先找出线程在各个变量的互斥关系,并发关系。如果是一读一写或两个都写,那么就是互斥关系。每一个互斥关系都需要一个信号量来调节。
semaphore mutex_y1; //mutex_y1用于thread1和thread3对变量y的互斥访问
semaphore mutex_y2; //mutex-y2用于thread2和thread3对变量y的互斥访问
smeaphore mutex_z; ///mutex_z用于变量z的互斥访问
//复数的结构类型定义
typedef struct
{
float a;
float b;
}cnum;
cnum x,y,z; //全局变量
//计算两个复数之和
cnum add(cnum p,cnum q)
{
cnum s;
s.a=p.a+q.a;
s.b=p.b+q.b;
return s;
}
thread1
{
cnum w;
wait(mutex_y1);
w=add(x,y); //thread1 和thread2都有y作为参数,是两个都读,不存在互斥问题,thread1对y的操作是读,thread3对y的操作是既读又写存在互斥
signal(mutex_y1);
...
}
thread2
{
cnum w;
wait(mutex_y2);
wait(mutex_z);
w=add(y,z); // 同样thread2和thread3对y的操作是读和写,需要互斥,对z的操作也需要互斥
signal(mutex_z);
signal(mutex_y2);
...
}
thread3
{
cnum w; //注意:w不是全局变量,只在自己的线程内作用,不属于临界资源
w.a=1;
w.b=2;
wait(mutex_z);
z=add(z,w);
signal(mutex_z);
wait(mutex_y1);
wait(mutex_y2);
y=add(y,w);
signal(mutex_y1);
signal(mutex_y2);
...
}
2.有A、B两人通过信箱进行辩论,每个人都从自己的信箱中取得对方的问题,将答案和向对方提出的问题组成一个新邮件放入对方的邮箱中。假设A的信箱最多放M个邮件,B的信箱最多放N个邮件。初始A的信箱有x个邮件,B的信箱有y个邮件。当信箱不空时,辩论者才能从邮箱中取邮件,否则等待。当信箱不满时,辩论者才能将邮件放入信箱中,否则需要等待。
semaphore mutex_A; //用于对A邮箱的互斥
semaphore mutex_B; //用于对B邮箱的互斥
semaphore Empty_A; //A邮箱中还可以放入的邮件数量
semaphore full_A; //A邮箱中的邮件数量
semaphore Empty_B; //A邮箱中还可以放入的邮件数量
semaphore full_B; //B邮箱中的邮件数量
Cobegin{
A{
while(true)
{
P(full_A);
P(mutex_A);
take out a mail from box A;
V(mutex_A);
V(Empty_A);
answer a question and put forward one;
P(Empty_B);
P(mutex_B);
put a new mail in box B;
V(mutex_B);
V(full_B);
}
}
B{
while(true)
{
P(full_B);
P(mutex_B);
take out a mail from box B;
V(mutex_B);
V(Empty_B);
answer a question and put forward one;
P(Empty_A);
P(mutex_A);
put a new mail in box A;
V(mutex_A);
V(full_A);
}
}
}end
3.系统中有多个生产者消费者进程,共享一个能存放1000件产品的缓冲区(初始为空)。当缓冲区未满时,生产者进程可以放入一个其生产的产品,否则等待;当缓冲区未空时,消费者进程可以从缓冲区取走一件产品,否则等待。要求一个消费者必须连续取走10件铲平后,其他消费者进程才可以取产品。
semaphore mutex1=1; //用于实现消费者连续取10个产品的互斥
semaphore mutex2=1; //用于实现缓冲区访问的互斥
semaphore empty=1000;
semaphore full=0;
producer()
{
while(1)
{
produce a product;
P(empty);
P(mutex2);
put product in the buffer;
V(mutex2);
V(full);
}
}
consumer()
{
while(1){
P(mutex1);
for(int i=0;i<10;++i){
P(full);
P(mutex2);
take out a product from the buffer;
V(mutex2);
V(empty);
consume this product;
}
V(mutex1);
}
}
4.某博物馆最多可容纳500人同时参观,有一个出入口,该初入口一次仅允许一个人通过。
semaphore empty=500;
semaphore mutex=1;
Cobegin
visitor process i:
{
P(empty);
P(mutex);
enter...;
V(mutex);
visit...;
P(mutex);
get out;
V(mutex);
V(empty);
}
5.某银行提供一个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上取一个号,取号机一次仅允许一个顾客使用。营业员通过叫号选择一位顾客为其服务。
semaphore empty=10; //空座位数量
semaphore mutex=1; //互斥使用取号机
semaphore full=0; //已经占空位数量
semaphore service=0; //等待叫号
process client i{
P(empty); //等空位
P(mutex);
take a number from the machine;
V(mutex);
V(full); //通知营业员有新顾客
P(service); //等待营业员叫号
accept serive;
}
process teller{
while(true){
P(full); //等待顾客
V(empty);//离开座位
V(service); //叫号 //这里我觉得应该是先叫号后离开座位,不过应该不影响
serve for the client
}
}
6.P1、P2、P3三个进程互斥使用一个包含N个单元的缓冲区,P1每次produce()一个正整数并用put()放入缓冲区某一空单元中;P2每次用getodd()从缓冲区取出一个奇数,并用countodd()统计奇数个数;P3每次用geteven()从缓冲区取出一个偶数,并用counteven()统计偶数个数。
semaphore mutex=1;
semaphore odd=0,even=0;
semaphore empty=N;
main()
cobegin()
{
process P1()
{
while(true)
{
x=produce();
P(empty);
P(mutex);
put();
V(mutex);
if(x%2==0)
V(even);
else
V(odd);
}
}
Process P2()
{
while(true)
{
P(odd);
P(mutex);
getodd();
V(mutex);
V(empty);
countodd();
}
}
process P3()
{
while(true)
{
P(even);
P(mutex);
geteven();
V(mutex);
V(empty);
counteven();
}
}
}coend;