2022.07.15
在一个仓库可以存放A、B两种产品,要求
semaphore mutex = 1;semaphore moreA = M-1;semaphore moreB = N-1;
productA(){ while(1){ P(moreA); P(mutex); put(A); V(mutex); V(moreB); }}
productB(){ while(1){ P(moreB); P(mutex); put(B); V(mutex); V(moreA); }}面包师有很多面包,由n名销售人员推销。每名顾客进店后取一个号,并且等待叫号,当一名销售人员空闲时,就叫下一个号。试设计一个使销售人员和顾客同步的算法。
// 下面是我自己想的方法semaphore seller = 0;semaphore customer = 0;
seller(){ while(1){ V(seller); P(customer); // serve(); }} customer(){ V(customer); P(seller); // buy();}我的想法,销售员和顾客的地位一样。两人碰成一对就可以产生一笔交易。
//下面是答案int i=0,j=0;semaphore mutex_i = 1; // 互斥访问计数器semaphore mutex_j = 1;
Consumer(){ //进入面包店; P(mutex_i); 取号; i++; V(mutex_i); // 等待叫号i并购买面包;}
Seller(){ while(1){ P(mutex_j); if(j<i){ 叫号j; j++; V(mutex_j); 销售面包; }else{ V(mutex_j); 休息片刻; } }}某工厂有两个生产车间和一个装配车间,两个生产车间分别生产 A,B两种零件,装配车间的任务是把A,B 两种零件组装成产品。两个生产车间每生产一个零件后,都要分别把它们送到专配车问的货架F1,F2上。F1存放零件A,F2存放零件B,F1和F2的容量均可存放10个零件。裝配工人每次从货架上取一个零件A和一个零件B后组装成产品。 请用 P,V操作进行正确管理。
semaphore f1 = 10;semaphore f2 = 10;semaphore A = 0;semaphore B = 0;semaphore mutex1 = 1;semaphore mutex2 = 1;
room1(){ while(1){ // produce A P(f1); P(mutex1); // put A V(mutex1); V(A); }}
room2(){ while(1){ // produce B P(f2); P(mutex2); // put B V(mutex2); V(B); }}
room3(){ while(1){ P(A); P(B); P(mutex1); // get A V(mutex1); V(f1); P(mutex2); // get B V(mutex2); V(f2); // prroduce with A and B }}寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为3个。每次入缸取水仅为 1桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
semaphore bucket = 3;semaphore place = 10;semaphore water = 0;semaphore mutex = 1; // 互斥的访问水缸semaphore mutex2 = 1;// 互斥的访问水井
small(){ P(place); // 确认有地方放再去打水(防止桶都拿走了,缸满了,老和尚没法喝水) P(bucket); // 拿桶 P(mutex2); // 取水 V(mutex2); P(mutex); // 倒水 V(mutex); V(water); V(bucket); // 放桶}
old(){ P(water); // 确认有水再去打水(防止桶都拿走了,缸空了,小和尚没办法打水) P(bucket); // 拿桶 P(mutex); // 取水 V(mutex); V(place); // 喝水 V(bucket); // 放桶}下图所示,三个合作进程P1,P2,P3,它们都需要通过同一设备输入各自的数据a,b,c,该输入设备必须互斥地使用,而且其第一个数据必须由P1进程读取,第二个数据必须由P2进程读取,第三个数据必须由P3进程读取.然后,三个进程分别对输入数据进行下列计算

P1: x = a+b;P2: y = a*b;P3: z = y+c-a;最后,P1进程通过所连接的打印机将计算结果 x,y,z的值打印出来。请用信号量实现它 们的同步。
semaphore g1,g2 = 0;semaphore c21,c22 = 0;//semaphore mutex=1; // 三个进程不会同时访问输入设备,所以不用mutex了
P1(){ // 获取数据 getA(); V(g1); // 计算数据 calculate(); // 打印输出 P(c21); print();}
P2(){ // 获取数据 P(g1); getB(); V(g2); V(c21); // 计算数据 calculate(); V(c22);}
P3(){ // 获取数据 P(g2); getC(); // 计算数据 P(c22); calculate();}
桥如下图所示。车流方向如箭头所示。回答如下问题: 1)假设桥上每次只能有一辆车行驶,试用信号灯的 P,V操作实现交通管理。 2)假设桥上不允许两车交会,但允许同方向多辆车一次通过(即桥上可有多辆同方向行驶的车)。试用信号灯的 P.V操作实现桥上的交通管理。

semaphore mutex=1;
sorth(){ P(mutex); // 过桥 V(mutex);}
north(){ P(mutex); // 过桥 V(mutex);}// 错误答案,没有考虑到第一个方向的车很多时,counter>0,对面来的同样会进去,产生冲突// 所以要拆解成两个计数器
int counter=0;semaphore mutex=1;semaphore mutex_c=1;
sorth(){ P(mutex_c); if(counter==0) P(mutex); count++; V(mutex_c); // 过桥 P(mutex_c); count--; if(counter==0) V(mutex); V(mutex_c);}
sorth(){ P(mutex_c); if(counter==0) P(mutex); count++; V(mutex_c); // 过桥 P(mutex_c); count--; if(counter==0) V(mutex); V(mutex_c);}int counterNS=0;int counterSN=0;semaphore mutex=1;semaphore mutex_NS=1;semaphore mutex_SN=1;
sorth(){ P(mutex_SN); if(counterSN==0) P(mutex); counterSN++; V(mutex_SN); // 过桥 P(mutex_SN); counterSN--; if(counterSN==0) V(mutex); V(mutex_SN);}
sorth(){ P(mutex_NS); if(counterNS==0) P(mutex); counterNS++; V(mutex_NS); // 过桥 P(mutex_NS); counterNS--; if(counterNS==0) V(mutex); V(mutex_NS);}假如有两个线程(编号为0和1)需要去访问同一个共享资源,为避免竞争状态的问题,我们必须实现一种互斥机制,使得在任何时候只能有一个线程访问这个资源。假设有如下一段代码:
bool flag[2]; // flag数组,初始化为FALSEEnter_Critical_Section(int my_thread_id, int other_thread_id){ while(flag[other_thread_id]==true); flag[my_thread_id]=true;}Exit_Critical_Section(int my_thread_id, int other_thread_id){ flag[my_thread_id]=false;}当一个线程想要访问临界资源时,就要掉用上述的这两个函数。例如,线程0的代码可能是这样的:
Enter_Critical_Section(0,1);
使用这个资源;
Exit_Critical_Section(0,1);
做其他的事情;
试问:
不可以,因为自己的flag标志成了正在使用前如果对方进程也正好要标记,两个进程都可以访问资源。
也不可以,那样造成死锁,两个进程都以为对方要进入但实际上都在等待。
自行车生产线上有一个箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮;又设有3名工人,其活动分别为:
// 工人1do{ 加工一个车架; 车架放到箱中;}while(1) // 工人2do{ 加工一个车轮; 车架放到箱中;}while(1) // 工人3do{ 取车架;取车轮; 组装;}while(1)是分别用信号量与PV操作实现三名工人的合作,解中不含死锁
// 错误答案,没有意识到车架或车轮完全占满存储区的情况
semaphore mutex = 1;semaphore place = N;semaphore 车架 = 0;semaphore 车轮 = 0;
p1(){ while(1){ //加工一个车架; P(place); P(mutex); //放入 V(mutex); V(车架); }}
p2(){ while(1){ //加工一个车轮; P(place); P(mutex); //放入 V(mutex); V(车轮); }}
p3(){ while(1){ P(车架); P(车轮); P(mutex); // 拿走车架车轮 V(mutex); V(place); }}// 正确答案
semaphore mutex = 1;semaphore placeJ = N-2;semaphore placeL = N-1;semaphore 车架 = 0;semaphore 车轮 = 0;
p1(){ while(1){ //加工一个车架; P(placeJ); P(mutex); //放入 V(mutex); V(车架); }}
p2(){ while(1){ //加工一个车轮; P(placeL); P(mutex); //放入 V(mutex); V(车轮); }}
p3(){ while(1){ P(车架); P(车轮); P(车轮); P(mutex); // 拿走车架车轮 V(mutex); V(placeJ); V(placeL); V(placeL); }}P,Q,R共享一个缓冲区,P,Q构成一对生产者-消费者,R既为生产者又为消费者。使用PV操作实现其同步。
semaphore mutex = 1; //共享缓冲区互斥访问semaphore product = 0;// 产品semaphore place = N; // 存储区大小
P(){ while(1){ // 生产商品 P(place); P(mutex); // 放入产品 V(mutex); V(product); }}
Q(){ while(1){ P(product); P(mutex); // 拿出产品 V(mutex); V(place); }}
R(){ while(1){ if(product==N){ P(product); P(mutex); // 拿出产品 V(mutex); V(place); } if(place==N){ // 生产商品 P(place); P(mutex); // 放入产品 V(mutex); V(product); } }}理发店里有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。若没有顾客,理发师便在理发椅上睡觉,一位顾客到来时,顾客必须叫醒理发师,若理发师正在理发时又有顾客来到,若有空椅子可坐,则坐下来等待,否则就离开。试用P,V操作实现,并说明信号量的定义和初值。
int waiting = 0; // 等待理发的顾客数int chairs = n; // 未顾客准备的椅子数semaphore customer=0,barber=0,mutex=1;
Barber(){ while(1){ P(customer); P(mutex); waiting--; V(barber); P(mutex); Cut_Hair(); }}
Customer(){ P(mutex); if(waiting<chairs){ waiting++; V(customer); V(mutex); P(barber); Get_Hair(); }else{ V(mutex); }}假设一个录像厅有1,2,3三种不同的录像片可由观众选择放映,录像厅的放映规则如下: 1)任一时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的,最后一名观众主动离开时结束当前录像片的放映。 2)选择当前正在放映的录像片的观众可立即进入,允许同时有多位选择同一种录像片的观众同时观看,同时观看的观众数量不受限制。 3)等待观看其他录像片的观众按到达顺序排队,当一种新的录像片开始放映时,所有等待观看该录像片的观众可依次序进入录像厅同时观看。用一个进程代表一个观众,要求:用信号量方法 PV 操作实现,并给出信号量定义和初始值。
semaphore s0=1,s1=1,s2=1;semaphore movie1=1,movie2=0,movie3=0;int count0=0,count1=0,count2=0;videoshow1(){ // 一个看movie1的观众 /* 观众入座 */ P(s0); count0++; if(count0==1) P(movie1); V(s0); /* 看电影 */ /* 观众离场 */ P(s0); count0--; if(count0==0) V(movie2); // 当天停止,下一个可以播放 V(s0);}
videoshow2(){ // 一个看movie2的观众 /* 观众入座 */ P(s1); count1++; if(count1==1) P(movie2); V(s1); /* 看电影 */ /* 观众离场 */ P(s1); count1--; if(count1==0) V(movie3); // 当天停止,下一个可以播放 V(s1);}
videoshow3(){ // 一个看movie1的观众 /* 观众入座 */ P(s2); count2++; if(count2==1) P(movie2); V(s2); /* 看电影 */ /* 观众离场 */ P(s2); count2--; if(count2==0) V(movie1); // 当天停止,下一个可以播放 V(s2);}南开大学和天津大学之间有一条弯曲的路,每次只九许一辆自行车通过,但中间有小的安全岛 M(同时允许两辆车通过),可供已进入两端的两辆小车错车,如下图所示。设计算法并使用P,V操作实现。

semaphore LT = 1;semaphore KN = 1;semaphore N = 1;semaphore T = 1;
N(){ P(N); P(KN); // go N to K; // go into M; V(KN); P(LT); // go L to T V(LT); V(N);}
T()同理公共汽车上驾驶员和售票员的活动分别如下图所示。驾驶员的活动:启动车辆,正常行车,到站停车;售票员的活动:关车门,售票,开车门。在汽车不断地到站、停车、行驶的过程中,这两个活动有什么同步关系?用信号量和B,V操作实现它们的同步

semaphore ticket = 0;semaphore stop = 1;
驾驶员(){ while(1){ P(ticket); 启动车辆(); 正常行车(); 到站停车(); V(stop); }}
售票员(){ while(1){ 乘客上下(); 关车门(); 售票(); V(ticket); P(stop); 开车门(); }}【2009 统考真题】三个进程P1,P2,P3互斥使用一个包含N(N>0)个单元的缓冲区。P1每次用produce()生成一个正整数并用put()送入缓冲区某一空单元;P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数;P3每次用geteven()从该缓冲区中取出一个偶数并用counteven()统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义(要求用伪代码描迷)。
semaphore mutex = 1; // 互斥访问存储区semaphore odd = 0; // 记录奇数个数semaphore even = 0; // 记录偶数个数semaphore place = N; // 记录空余存储区数量
P1(){ int number; while(1){ number = produce(); P(place); P(mutex); put(number); V(mutex); if(number%2) V(odd); else V(even); }}
P2(){ int number; while(1){ P(odd); P(mutex); number = getodd(); V(mutex); V(place); countodd(); }}
P2(){ int number; while(1){ P(even); P(mutex); number = geteven(); V(mutex); V(place); counteven(); }}【2011 统考真题】某银行提供1个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅九许一位顾客使用。当营业员空闲时,通过叫号选取一位顾客,并为其服务。顾客和营业员的活动过程描述如下:
cobegin{ provess 顾客i { 从取号机获取一个号码; 等待叫号; 获取服务; } process 营业员 { while(TRUE) { 叫号; 为客户服务; } }}coend请添加必要的信号量和P,V[或 wait(), signal()]操作,实现上述过程中的互斥与同步要求写出完整的过程,说明信号量的含义并赋初值。
x
semaphore mutex = 1; // 互斥访问取号机semaphore officer = 0; // 互斥访问营业员semaphore wait = 10; // 空位semaphore customer = 0;// 等待的人
cobegin{ provess 顾客i { P(wait); P(mutex); 从取号机获取一个号码; V(mutex); V(customer); P(officer); // 等待叫号; V(wait); 获取服务; } process 营业员 { while(TRUE) { P(customer); V(officer); // 叫号; 为客户服务; } }}coend【2013 统考真题】某博物馆最多可容纳 500人同时参观,有一个出入口,该出入口一次仅允许一人通过一人通过。参观者的活动描述如下:
cobegin{ 参观者进程i: { ... 进门; ... 参观; ... 出门; ... }}coendsemaphore place = 500;semaphore mutex = 1;cobegin{ 参观者进程i: { P(place) P(mutex); 进门; V(mutex); 参观; P(mutex); 出门; V(mutex); V(place); }}coend【2014统考真题】系統中有多个生产者进程和多个消费者进程,共享一个能存放 1000件产品的环形缓冲区(初始为空)。缓冲区未满时,生产者进程可以放入其生产的一件产品,否則等待;缓冲区未空时,消费者进程可从缓冲区取走一件产品,否则等待。要求一个消费者进程从缓冲区连续取出 10件产品后,其他消费者进程才可以取产品。请使用信号量P,V (waito,signal()操作实现进程间的互斥与同步,要求写出完整的过程,并说明所用信号量的含义和初值。
x
int count = 0;semaphore cus = 1;semaphore place = 1000;semaphore product = 0;semaphore mutex = 1;
producer(){ while(1){ P(place); P(mutex); put(); V(mutex); V(product); }}
customer(){ while(1){ P(cus); for(int i;i<10;i++){ P(product); P(mutex); get(); V(mutex); V(place); } V(cus); }}【2015统考真题】有A,B两人通过信箱进行辨论,每个人都从自己的信箱中取得对方的问题。将答案和向对方提出的新问题组成一个邮件放入对方的邮箱中。假设A的信箱最多放M个邮件,B的信箱最多放N个邮件。初始时 A的信箱中有x个邮件(0<x<M),B的信箱中有y个邮件(0<y<N)。辦论者每取出一个邮件,邮什数减 1。A和B两人的操作过程描述如下:
A{ while(TRUE){ 从A的信箱中取出一个邮件; 回答问题并提出一个新问题; 将新邮件放入B的信箱; }}
B{ while(TRUE){ 从B的信箱中取出一个邮件; 回答问题并提出一个新问题; 将新邮件放入A的邮箱; }}当信箱不为空时,辨论者才能从信箱中取邮件,否则等待。当信箱不满时,辩论者才能将新邮件放入信箱,否则等待。请添加必要的信号量和P,VI或wait0, signalO 1 操作,以实现上述过程的同步。要求写出完整的过程,并说明信号量的含义和初值。
semaphore Anum = x;semaphore Bnum = y;semaphore Aplace = N-x;semaphore Bplace = M-y;semaphore Amutex = 1;semaphore Bmutex = 1;A{ while(TRUE){ P(Anum); P(Amutex); 从A的信箱中取出一个邮件; V(Amutex); V(Aplace); 回答问题并提出一个新问题 P(Bplace); P(Bmutex); 将新邮件放入B的信箱; V(Bmutex); V(Bnum); }}
B{ while(TRUE){ P(Bnum); P(Bmutex); 从B的信箱中取出一个邮件; V(Bmutex); V(Bplace); 回答问题并提出一个新问题; P(Aplace); P(Amutex); 将新邮件放入A的邮箱; V(Amutex); V(Anum); }}【2017统考真题】某进程中有了个并发执行的线程threadl,thread2 和thread3,其伪代码如下所示。
//复数的结构类型定义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 = 1; z = add(z,w); y = add(y,w); // ...}请添加必要的信号量和P,V[ 或 wait(), signal() ]操作,要求确保线程互斥访问临界资源,并且最大限度地并发执行。
x
//复数的结构类型定义typedef struct{ float a; float b;}cnum;cnum x,y,z;//全局变量
semaphore Y=0;
// 计算两个复数之和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; P(Y); w = add(x,y); // ...}
thread2{ cnum w; P(Y); w = add(y,z); // ...}
thread3{ cnum w; w.a = 1; w.b = 1; z = add(z,w); y = add(y,w); V(Y);V(Y); // ...}【2019统考真题】有n(n≥3)名哲学家團坐在一张園桌边,每名哲学家交替地就餐和思考。在國東中心有m(m≥1)个碗,每两名哲学家之问有一根筷子。每名哲学家必须取到一个碗和两侧的筷子后,才能就餐,进餐完毕,将碗和筷子放回原位,并继续思考. 为使尽可能多的哲学家同时就餐,且防止出现死锁现象,请使用信号量的P,V操作[ wait(),signal()操作】描述上述过程中的至斥与同步,并说明所用信号量及初值的含义。
semaphore mutex = 1; // 保证哲学家需要一次性获得两个筷子semaphore bowl = m;semaphore k[n];for(int i=0;i<n;i++) k[i] = 1; phi(i){ // i = 0,1,2,3... while(1){ P(bowl); P(mutex); P(i); P((i+1)%n); V(mutex); // 吃饭 P(mutex); V(i); V((i+1)%n); V(mutex); V(bowl); }}方法2:利用🥣碗的数量避免死锁,只需要让bowl = min{n-1,m}
【2020 统考真题】现有5个操作A、B、C、D和E,操作C 必须在A和B完成后执行,操作E必须在C和D完成后执行,请使用信号量的wait()、signal()操作(P、V操作)描述上述操作之间的同步关系,并说明所用信号量及其初值。
x
A,B -> CC,D -> E semaphore C_A=0,C_B=0;semaphore E_C=0,E_D=0;
A{ V(C_A);}B{ V(C_B);}C{ P(C_A); P(C_B); V(E_C);}D{ V(E_D);}E{ P(C_E); P(D_E);}【2021 统考真题】下表给出了整型信号量S 的wait()和 signal()操作的功能描述,以及来用开/关中断指令实现信号量操作互斥的两种方法。
x
// 功能描述semaphore S;wait(S){ while(S<=0); S=S-1;}signal(S){ S=S+1;}
// 方法1semaphore S;wait(S){ 关中断; while(S<=0); S=S-1; 开中断;}signal(S){ 关中断; S=S+1; 开中断;}
// 方法2semaphore S;wait(S){ 关中断; while(S<=0){ 开中断; 关中断; } S=S-1; 开中断;}signal(S){ 关中断; S=S+1; 开中断;}回答下列问题 1)为什么在wait()和 signal()操作中对信号量S的访问必须互斥执行?
因为S属于共享资源,多个进程都可以通过wait(),signal()对S进行读写,所以他们不可以同时访问(互斥访问)。
2)分别说明方法1和方法2是否正确。若不正确,请说明理由。
方法1不正确,如果S≤0,方法一将持续等待资源,并且由于设置了开中断,该进程不能下处理机,新的进程没办法继续提供资源。方法二正确,检查S后,开中断,允许别的进程抢占处机。
3)用户程序能否使用开/关中断指令实现临界区互斥?为什么?
不能。因为用户程序不能定义开中断和关中断,只能由操作系统进行,运行在内核态。