PV操作
2016
某系统允许最多10个进程同时读文件F,当同时读文件F的进程不满10个时,欲读该文件的其他文件可立即读,当已有10个进程在读文件F时读,其他欲读文件F的进程必须等待,直至有进程读完后退出方可去读
- 在实现管理时应采用同步方式还是互斥方式
- 写出用PV操作实现管理时应定义的信号量及其初值
- 写出进程并发执行时的程序
- 互斥
- 定义一个信号量S,初值S=10
semaphore S = 10;
process reader iP(S);read file F;V(S);
2015
什么是前趋图,用前趋图绘出下列程序段的前趋关系
 S1 :a = x + y
 S2 :b = z + 3
 S3 :c = a + b
 S4 :s = c + a
前趋图是一个有向无环图,用于描述进程之间执行的前后关系
 ![![[Pasted image 20241118184722.png]]](https://i-blog.csdnimg.cn/direct/303769a908184faca71664392e002286.png)
2
在一个仓库中可以存放A和B两种产品,要求:
- 每次只能存入一种产品。
- A产品数量-B产品数量<M,其中M是正整数。
- B产品数量-A产品数量<N,其中N是正整数。
 假设仓库的容量是无限的,试用PV操作描述产品A和B的入库过程。
使用信号量mutex控制两个进程互斥访问临界资源仓库
 使用同步信号量Sa和Sb分别表示产品A与B的还可容纳的数量差,以及产品B与A的还可容纳的数量差
semaphore Sa = M - 1, Sb = N - 1;
semaphore mutex = 1;process_A()
{while (1){P(Sa);P(mutex);A产品进入仓库;V(mutex);V(Sb);}
}process_B()
{while (1){P(Sb);P(mutex);B产品进入仓库;V(mutex);V(Sa);}
}
5
某寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。
 水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为3个。每次入缸取水仅为1桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
从井中取水并放入水缸是一个连续的动作,可视为一个进程
 从缸中取水可视为另一个进程
 设水缸与水井为临界资源,引入well和vat
 三个水桶无论是从井中取水还是将水倒入水缸都是一次一个,给一个信号量pail,抢不到水桶的进程只好等待
 水缸满时,不可以再放水,设置empty信号量来控制入水量
 水缸空时,不可以取水,设置full信号量来控制
sempaphore well = 1;        // 用于互斥地访问水井
sempaphore vat = 1;         // 用于互斥地访问水缸
sempaphore empty = 10;      // 用于表示水缸中剩余空间能容纳的水的桶数
sempaphore full = 0;        // 表示水缸中的水的桶数
sempaphore pail = 3         // 表示有多少个水桶可以用,初值为3// 从水缸中打水
while (1)
{P(full);P(pail);P(vat);从水缸中打一桶水;V(vat);V(empty);喝水;V(pail);
}// 从井中打水
while (1)
{P(empty);P(pail);P(well);从井中打一桶水;V(well);P(vat);将水倒入水缸中;V(vat);V(full);V(pail);
}
6
如下图所示,三个合作进程P1,P2,P3,它们都需要通过同一设备输入各自的数据a,b,c,
 该输入设备必须互斥地使用,而且其第一个数据必须由P1进程读取,第二个数据必须由P2进程读取,第三个数据必须由P3进程读取。
 ![![[Pasted image 20241118185608.png]]](https://i-blog.csdnimg.cn/direct/efde9927bd4c4175925f5021d346b997.png)
然后,三个进程分别对输入数据进行下列计算:
 P1:x = a + b;
 P2:y = a x b;
 P3:z = y + c - a;
 最后,P1进程通过所连接的打印机将计算结果x,y,Z的值打印出来。
 请用信号量实现它们的同步。
为了控制三个进程依次使用输入设备进行输入,需要分别设置三个信号量S1,S2,S3,其中S1的初值为1,S2和S3的初值为0
 使用上述信号量后,三个进程不会同时使用输入设备,因此不必再为输入设备设置互斥信号量
 还需要设置信号量Sb,Sy,Sz来表示数据b是否已经输入,以及y,z是否已计算完成,它们的初值均为0
 P1
 S1初始为1,P(S1),申请S1,S1–
 S2初始为0,V(S2),释放S2,S2++
 计算x要用到b,申请Sb,P(Sb),Sb–
 要打印xyz,要申请Sy和Sz,P(Sy),P(Sz)
 P2
 S2为1,P(S2),申请S2,S2–
 S3初始为0,释放S3,S3++
 Sb初始为0,当b输入完成后,V(Sb),Sb+1;
 Sy初始为0,当计算完y后,V(Sy),释放一个y,Sy+1;
 P3
 输入数据c要用输入设备,申请S3,P(S3)
 计算要使用y,所以要P(Sy),申请y
 Sz初始为0,当计算完z后,V(Sz),释放一个z,Sz+1;
P1()
{P(S1);从输入设备输入数据a;V(S2);P(Sb);x = a + b;P(Sy);P(Sz);使用打印机打印出x,y,z的结果;
}P2()
{P(S2);从输入设备输入数据b;V(S3);V(Sb);y = a + b;V(Sy);
}P(3)
{P(S3);从输入设备输入数据c;P(Sy);z = y + c - a;V(Sz);
}
7
有桥如下图所示。车流方向如箭头所示。回答如下问题:
- 假设桥上每次只能有一辆车行驶,试用信号灯的PV操作实现交通管理。
- 假设桥上不允许两车交会,但允许同方向多辆车一次通过(桥上可有多辆同方向行驶的车)。试用信号灯的PV操作实现桥上的交通管理。
 ![![[Pasted image 20241118185705.png]]](https://i-blog.csdnimg.cn/direct/145f3e7ab84349028a091d894bd5b7a3.png) 
桥上每次只能有一辆车通过,所以只要设置一个互斥信号量bridge就可以判断桥是否使用
 若在使用中,等到;若无人使用,则执行P操作进入;出桥后,执行V操作
semaphore bridge = 1;
NtoS()
{P(bridge);通过桥;V(bridge);
}StoN()
{P(bridge);通过桥;V(bridge);
}
桥上可以同方向多车行驶,需要设置bridge,还需要对同方向车辆计数,
 为了防止同方向计数中同时申请bridge造成同方向不可同时行车的问题,需要对计数过程加以保护,因此设计信号量mutexSN和mutexNS
- 计数器 - countSN:记录当前正在从南到北过桥的汽车数量。
- countNS:记录当前正在从北到南过桥的汽车数量。
 
- 信号量 - mutexSN:用于对 countSN 的访问提供互斥保护。
- mutexNS:用于对 countNS 的访问提供互斥保护。
- bridge:控制桥的访问,保证同一时刻只有一个方向的车可以通过桥。
 
- 函数 - P(semaphore):信号量的减操作(等待信号量)。
- V(semaphore):信号量的加操作(释放信号量)。
 
从南到北
- 进入临界区: - 调用 P(mutexSN) 获取对 countSN 的独占访问权限。
- 检查 countSN 是否为 0: - 如果是 0,说明桥上没有从南到北方向的车。
- 调用 P(bridge) 占用桥,防止其他方向的车进入。
 
- 将 countSN 增加 1。
- 释放 mutexSN,其他南向车辆可以检查 countSN。
 
- 过桥: - 模拟车辆过桥的操作。
 
- 离开桥: - 再次调用 P(mutexSN) 进入临界区,减少 countSN 的值。
- 检查 countSN 是否为 0: - 如果是 0,说明当前方向的车辆已经全部过桥,释放桥的控制权(V(bridge))。
 
- 释放 mutexSN。
 
- 信号量保护: - mutexSN 和 mutexNS 确保对计数器的访问是线程安全的。
- bridge 确保同一时刻只有一个方向的车辆可以通过桥。
 
- 连续性: - 当桥上有一个方向的车辆在通行时,同方向的其他车辆可以加入,不需要等待桥的重新分配。
 
- 方向切换: - 当某一方向的最后一辆车离开桥后(countSN 或 countNS 变为 0),桥释放(调用 V(bridge)),另一方向的车可以进入桥。
 
int countSN = 0;        // 用于表示从南到北的汽车数量
int countNS = 0;        // 用于表示从北到南的汽车数量
semaphore mutexSN = 1;  // 用于保护 countSN
semaphore mutexNS = 1;  // 用于保护 countNS
semaphore bridge = 1;   // 用于互斥地访问桥StoN()
{P(mutexSN)if (countSN == 0)P(bridge);countSN++;V(mutexSN);过桥;P(mutexSN);countSN--;if (countSN == 0)V(bridge);V(mutexSN);
}NtoS()
{P(mutexNS)if (countNS == 0)P(bridge);countNS++;V(mutexNS);过桥;P(mutexNS);countNS--;if (countNS == 0)V(bridge);V(mutexNS);
}
9
设自行车生产线上有一个箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮;又设有3名工人,其活动分别为:
 工人1活动:
do
{加工一个车架;车架放入箱中;
}while(1)
工人2活动:
do
{加工一个车轮;车轮放入箱中;
}while(1)
工人3活动:
do
{箱中取一个车架;箱中取二个车轮;组装为一台车;
}while(1)
试分别用信号量与PV操作实现三名工人的合作,要求解中不含死锁。
首先不考虑死锁的问题,1和3,2和3构成生产者消费者关系,这两对关系通过共同的缓冲区相联系
 箱子中的空位置相当于1和2的资源,车架和车轮相当于3的资源
 为防止死锁的产生,箱子中车架的数量不可超过N-2,车轮的数量不可超过N-1
semaphore empty = N;       //空位置
semaphore wheel = 0;       //车轮
semaphore frame = 0;       //车架
semaphore s1 = N - 2;      //车架最大数
semaphore s2 = N - 1;      //车轮最大数工人1
do
{加工一个车架;P(S1);P(empty);车架放入箱子;V(frame);
}while (1);工人2
do
{加工一个车轮;P(S2);P(empty);车轮放入箱子;V(wheel);
}while (1);工人3
do
{P(frame);取一个车架;V(empty);V(S1);P(wheel);P(wheel);取两个车轮;V(empty);V(empty);V(S2);V(S2);组装;
}while (1);
10
设P,Q,R共享一个缓冲区,P,Q构成一对生产者-消费者,R既为生产者又为消费者,若缓冲区为空,则可以写入;若缓冲区不空,则可以读出。
 使用PV操作实现其同步。
设三个信号量,full,empty,mutex,
 full和empty用来控制缓冲区状态,mutex用来互斥进入
 R既为消费者又是生产者,因此必须在执行前判断状态,若empty = 1,则执行生产者功能;若full = 1,执行消费者功能
semaphore full = 0;
semaphore empty = 1;
semaphore mutex = 1;process P()
{while (true){P(empty);P(mutex);Product One;v(mutex);V(full);}
}process Q()
{while (true){P(full);P(mutex);Consume One;v(mutex);V(empty);}
}process R()
{if (empty == 1){P(empty);P(mutex);Product One;v(mutex);V(full);	}if (full == 1){P(full);P(mutex);Consume One;v(mutex);V(empty);}
}
12
假设一个录像厅有1,2,3三种不同的录像片可由观众选择放映,录像厅的放映规则如下:
- 任意时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的,最后一名观众主动离开时结束当前录像片的放映。
- 选择当前正在放映的录像片的观众可立即进入,允许同时有多位选择同一种录像片的观众同时观看,同时观看的观众数量不受限制。
- 等待观看其他录像片的观众按到达顺序排队,当一种新的录像片开始放映时,所有等待观看该录像片的观众可依次序进入录像厅同时观看。
 用一个进程代表一个观众,
 要求:用信号量方法PV操作实现,并给出信号量定义和初始值。
电影院一次只能放映一部影片,希望观看另外两部的用户只能等待
 分别为三个影片设置三个信号量s0,s1,s2,初值分别为1,1,1
 电影院一次只能放一部影片,需要互斥使用
 由于观看影片的观众有多个,必须分别设置三个计数器,统计观众个数
 计数器是共享变量,需要互斥使用
- 共享资源控制信号量:s- s是一个二元信号量,控制资源访问权限。
- 任意一个组的进程在访问共享资源前,必须获得 s,而当所有该组进程退出资源时,才释放s。
 
- 组内进程同步信号量:s0,s1,s2- 每个组的进程都有一个独立的信号量(如 s0,s1,s2),用于保护对组内计数器count0,count1,count2的操作,防止多个进程同时修改这些计数器导致竞态条件。
 
- 每个组的进程都有一个独立的信号量(如 
- 计数器:count0,count1,count2- 每组都有一个计数器,用于记录当前正在访问共享资源的该组进程数目。
- 第一个进入共享资源的进程会锁定资源,最后一个退出资源的进程会解锁资源。
 
程序运行流程
process 1()
 
- 进入资源时: - 获取组信号量 s0,修改组计数器count0。
- 如果是第一个进入资源的进程(count0 == 1),锁定共享资源信号量s。
- 释放组信号量 s0,允许其他进程修改组计数器。
- 进入资源(看影片)。
 
- 获取组信号量 
- 退出资源时: - 获取组信号量 s0,修改组计数器count0。
- 如果是最后一个退出资源的进程(count0 == 0),释放共享资源信号量s。
- 释放组信号量 s0。
 
- 获取组信号量 
核心功能
- 互斥访问: - 每个组的进程在访问共享资源时,确保独占。
- 使用 s信号量控制资源访问,防止不同组的进程同时访问资源。
 
- 组内进程同步: - 同组的进程可以同时访问资源。
- 使用 s0,s1,s2信号量保护对计数器的访问,防止竞态条件。
 
semaphore s = 1, s0 = 1, s1 = 1, s2 = 1;
int count0 = 0, count1 = 0, count2 = 0;process 1()
{P(s0);count0 = count0 + 1;if (count0 == 1)P(s);V(s0);看影片;P(s0);count0 = count0 - 1;if (count0 == 0)V(s);V(s0);
}process 2()
{P(s1);count1 = count1 + 1;if (count1 == 1)P(s);V(s1);看影片;P(s1);count1 = count1 - 1;if (count1 == 0)V(s);V(s1);
}process 1()
{P(s2);count2 = count2 + 1;if (count2 == 1)P(s);V(s2);看影片;P(s2);count2 = count2 - 1;if (count2 == 0)V(s);V(s2);
}
13
设公共汽车上驾驶员和售票员的活动分别如下图所示。
 ![![[Pasted image 20241118195422.png]]](https://i-blog.csdnimg.cn/direct/aa6ec693628a42f3a10687f37bbd1969.png)
驾驶员的活动:启动车辆,正常行车,到站停车;
 售票员的活动:关车门,售票,开车门。
 在汽车不断地到站、停车、行驶的过程中,这两个活动有什么同步关系?
 用信号量和PV操作实现它们的同步。
汽车行驶过程中,驾驶员活动与售票员活动之间的同步关系为,
 售票员关门后,向驾驶员发开车信号,驾驶员接到开车信号后启动车辆,在汽车行驶过程中售票员售票,到站时驾驶员停车,售票员在车停后开门让乘客下车
 驾驶员启动车辆的动作必须与售票员关车门的动作同步
 售票员开门的动作必须与驾驶员停车同步
 应设置两个信号量S1,S2
 S1表示是否允许驾驶员启动汽车,初值为0
 S2表示是否允许售票员开门,初值为0
主要信号量分析
- S1信号量:- 初值为 0,表示通知司机开始开车。
- 售票员在关车门后通过 V(S1)通知司机开车。
- 司机通过 P(S1)等待售票员的通知。
 
- S2信号量:- 初值为 0,表示通知售票员可以开车门和上下乘客。
- 司机在停车后通过 V(S2)通知售票员。
- 售票员通过 P(S2)等待司机的通知。
 
程序的同步机制
- 售票员和司机同步: - 售票员调用 V(S1)后,司机通过P(S1)接收到通知,开始驾驶。
- 司机调用 V(S2)后,售票员通过P(S2)接收到通知,开车门并上下乘客。
 
- 售票员调用 
- 过程的互斥和顺序控制: - 售票员不能在司机开车前打开车门(需要等待司机通知)。
- 司机不能在售票员关车门之前开始驾驶(需要等待售票员通知)。
 
semaphore S1 = 0, S2 = 0;process driver()
{while (1){P(S1);Start;Driving;Stop;V(S2);}
}process Conductor()
{while (1){关车门;V(S1);售票;P(S2);开车门;上下乘客;}
}
- 售票员关车门并通知司机准备开车。
- 司机开车、驾驶、停车,并通知售票员完成驾驶。
- 售票员开车门,进行上下乘客的操作。