新浪博客

同步问题

2012-06-06 14:04阅读:
同步与互斥习题及解答:
1. 何谓与时间有关的错误? 举例说明之。
答:并发进程的执行实际上是进程活动的某种交叉,某些交叉次序可能得到错误结果。由于具体交叉的形成与进程的推进速度有关,而速度是时间的函数,因而将这种错误称为与时间有关的错误。
例如,两个并发进程的程序如下:
int n=0;
main( ){
创建进程A;
创建进程B;
};

A( ){
while(1){
n++;
}
};
B( ){
while(1){
睡眠一段时间;
printf(“%d”,n);
n=0; }
};
假设进程A被部署在公园入口的终端上,用来记录一段时间内进入公园的人数,进程B被部署在公园的控制中心,用来输出一段时间内进入公园的总人数。进程A和进程B共享全局变量n,n表示记录下的人数。如果在进程B执行完打印语句后被进程A打断,进程A执行了若干次变量自增语句,之后进程B接着执行清0语句,那么进程A对n的累加丢失了,相当于进程B被打断的这段时间内进入公园的人没有被记录下来。发生与时间有关的错误。
2. 有人说,假设两个进程之间没有共享内存,则二者之间没有公共变量,这种说法准确吗? 说明原因。
答:如果只从用户空间考虑,这种说法是正确的。但从操作系统的角度来说并不准确。两个没有公共内存的用户进程可能同时(宏观)进入操作系统,并访问操作系统空间中的公共变量。
3.何谓忙式等待? 是否还有其它方式的等待? 比较它们之间的联系和差别。
答:不进入等待状
态的等待称为忙式等待。另一种等待方式是阻塞式等待,进程得不到共享资源时将进入阻塞状态,让出CPU给其他进程使用。忙等待和阻塞式等待的相同之处在于进程都不具备继续向前推进的条件,不同之处在于处于忙等待的进程不主动放弃CPU,尽管CPU可能被剥夺,因而是低效的;而处于阻塞状态的进程主动放弃CPU,因而是高效的。
4.下列进程互斥方法哪些存在忙式等待问题?
(1)软件: 面包店算法(2) 硬件: TS指令(3) 关中断指令
答:(1)、(2)存在忙等待问题。
5.为何开关中断进程互斥方法仅在单CPU系统中是有效的?
答:关中断方法不适用于多CPU系统,因为关中断只能保证CPU不由一个进程切换到另外一个进程,从而防止多个进程并发地进入公共临界区域。但即使关中断后,不同进程仍可以在不同CPU上并行执行关于同一组共享变量的临界区代码.
6.在多处理机系统中,软件互斥方法是否有效?为什么?
  答:依然有效。多处理机并行与单处理并发之间的差别在于程序交叉的粒度,单处理机机环境中进程交叉发生在指令之间,多处理机环境中进程交叉发生在指令周期之间。由于纯软件互斥算法并不依赖特殊的硬件指令(如test_and_set),指令之间的交叉与指令周期之间的交叉结果相同。
7.试分析临界区域的大小与系统并发性之间的关系。
答:关于同一组变量的临界区域是不能并发执行的代码,临界区越大,并发性越差,因而编写并发程序应尽量缩小临界区域范围。
8.设CR1是关于一组共享变量SV1的临界区域,CR2是关于另外一组共享变量SV2的临界区域,当进程P1进入CR1时,进程P2是否可以进入CR2? 为什么?
答:可以。因为互斥是在变量级别上的,多个进程同时进入关于不同变量的临界区不会引起与时间有关的错误。
9.Lamport面包店互斥算法是否会出现饿死情况?
  不会,该算法是公平的。假定系统中共有n个进程,每个想要进入临界区域的进程(线程)在最坏的情况下需要等待其它n-1个进程进入并离开临界区域之后即可获得进入临界区域的机会,因而存在(忙式)等待的上界。
10.试用信号灯和PV操作实现临界区语句:
region <共享变量> do <语句>
变量类型<共享变量>
答:
semaphore s=1;
P(s);
<语句>
V(s);
11. 由V操作唤醒的进程是否一定能够直接进入运行状态? 举例说明之。
答:否。一般来说,唤醒是将进程状态由等待状态变成就绪状态,而就绪进程何时获得处理机则是由系统的处理机调度策略确定的。如果采用抢占式优先级调度算法,并且被唤醒的进程是当前系统中优先级最高的进程,那么该进程将被调度执行,其状态变成运行态。如果该进程不是系统中优先级最高的进程或系统采用其它调度算法,那么该进程不会被调度执行,其状态将维持在就绪态。
12. 设S1和S2为两个信号灯变量,下列八组P、V操作哪些可以同时进行? 哪些不能同时进行? 为什么?
(1)P(S1),P(S2) (2)P(S1),V(S2)
(3)V(S1),P(S2) (4)V(S1),V(S2)
(5)P(S1),P(S1) (6)P(S2),V(S2)
(7)V(S1),P(S1) (8)V(S2),V(S2)
答:能同时进行的包括:(1)、(2)、(3)、(4)。这些操作涉及不同信号灯变量,属于关于不同组共享变量的临界区。不能同时进行的包括:(5)、(6)、(7)、(8)。这些操作涉及相同的信号灯变量,属于关于同一组共享变量的临界区。
13. 对于生产者—消费者问题,假设缓冲区是无界的,试用信号灯与PV操作给出解法。
答:由于是无界缓冲区,所以生产者不会因得不到缓冲区而被阻塞,不需要对空缓冲区进行管理,可以去掉在有界缓冲区中用来管理空缓冲区的信号量及其PV操作。
semaphore mutex_in=1;
semaphore mutex_out=1;
semaphore empty=0;
int in=0,out=0;

生产者活动:
while(1){
produce next product;
P(mutex_in);
add the product to buffer[in];
in++;
v(mutex_in);
V(empty);
}
消费者活动:
while(1){
P(empty);
P(mutex_out);
take the product from buffer[out];
out++;
V(mutex_out);
}
14. 设有一个可以装A、B两种物品的仓库,其容量无限大,但要求仓库中A、B两种物品的数量满足下述不等式:
-M≤A物品数量-B物品数量≤N
其中M和N为正整数。 试用信号灯和PV操作描述A、B两种物品的入库过程。
答:已知条件 -M≤A物品数量-B物品数量≤N 可以拆成两个不等式,即
A物品数量-B物品数量≤N
B物品数量-A物品数量≤M
这两个不等式的含义是:仓库中A物品可以比B物品多,但不能超过N个;B物品可以比A物品多,但不能超过M个。
semaphore a=n;
semaphore b=m;
void main(){
createprocess(A,…);
createprocess(B,…);
}
A物品入库:
void A(){
while(1){
P(a);
A物品入库;
V(b);
}
}
B物品入库:
void B(){
while(1){
P(b);
B物品入库;
V(a);
}
}
15. 试用信号灯与PV操作实现司机与售票员之间的同步问题。设公共汽车上有一个司机和一个售票员,其活动如下图
所示。

为了安全起见,显然要求: (1)关车门后方能启动车辆;(2)到站停车后方能开车门。亦即“启动车辆”这一活动应当在“关车门”这一活动之后,“开车门”这一活动应当在“到站停车”这一活动之后。
解:如果进程P2尚未推进到②处时,进程P1已经推进到①处,则P1应等待直到P2推进到②处为止;同样,如果进程P1尚未推进到③处时,进程P2已经推进到④处,则P2应等待直到P1推进到③处为止。如果进程P1在①处发生了等待,则当进程P2执行到②处时应将P1唤醒;同样,如果进程P2在④处发生了等待,则当进程P2执行到③处时应将P1唤醒。用信号量和P、V操作解决这一问题,需要定义两个信号量,一个信号量start表示是否允许司机启动车辆,另一个信号量open表示是否允许售票员开车门。初始状态是车停在始发站,车门开着,等待乘客上车。因此,两个信号量的初值都是0。
semaphore start=0;
semaphore open=0;


司机的活动:
P1: do{
P(start);
启动车辆;
正常行车;
到站停车;
V(open);
}while (1);

售票员的活动:
P2: do{
关车门;
V(start);
售票;
P(open);
开车门;
}while (1);
16. 设有A、B、C三组进程,它们互斥地使用某一独占型资源R,使用前申请,使用后释放。资源分配原则如下:
(1) 当只有一组申请进程时,该组申请进程依次获得R;
(2) 当有两组申请进程时,各组申请进程交替获得R,组内申请进程依次获得R;
(3) 当有三组申请进程时,各组申请进程轮流获得R,组内申请进程依次获得R。
试用信号灯和PV操作分别给出各组进程的申请活动程序段和释放活动程序段。
解:
int free=1;//设备状态标志
semaphore mutex=1;
semaphore qa=qb=qc=0; //各组等待队列
int counta=countb=countc=0;//等待队列长度
A组申请:
P(mutex);
if(free==1){
free=0;
V(mutex);
}
else{
counta++;
V(mutex);
P(qa);
}
A组释放:
P(mutex);
if(countb>0){
countb--;
V(qb);
}else{
if(countc>0){
countc--;
V(qc);
}else{
if(counta>0){
counta--
V(qa);
}else{
free=1;
}
}
}
}
A组进程活动可以给出B组和C组进程活动。
17. 设自行车生产线上有一只箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮; 又设有三个工人,其活动分别为:
工人1活动:
do {
加工一个车架;
车架放入箱中;
}while(1)
工人2活动:
do {
加工一个车轮;
车轮放入箱中;
}while(1)
工人3活动:
do {
箱中取一车架;
箱中取二车轮;
组装为一台车;
}while(1)
试分别用信号灯与PV操作、管程、会合实现三个工人的合作,要求解中不含死锁。
解:用信号灯与PV操作实现三个工人的合作,管程与会合解法可仿照给出。
首先不考虑死锁问题,工人1与工人3、工人2与工人3构成生产者与消费者关系,这两对生产/消费关系通过共同的缓冲区相联系。从资源的角度来看,箱子中的空位置相当于工人1和工人2的资源,而车架和车轮相当于工人3的资源。定义三个信号灯如下:
semaphore empty=N;//空位置
semaphore wheel=0;//车轮
semaphore frame=0;//车架
三位工人的活动分别为:
工人1活动:
do {
加工一个车架;
P(empty);
车架放入箱中;
V(frame);
}while(1)
工人2活动:
do {
加工一个车轮;
P(empty);
车轮放入箱中;
V(wheel);
}while(1)
工人3活动:
do {
P(frame);
箱中取一车架;
V(empty);
P(wheel);
P(wheel);
箱中取二车轮;
V(empty);
V(empty);
组装为一台车;
}while(1)
分析上述解法易见,当工人1推进速度较快时,箱中空位置可能完全被车架占满或只留有一个存放车轮的位置,而当此时工人3同时取2个车轮时将无法得到,而工人2又无法将新加工的车轮放入箱中;当工人2推进速度较快时,箱中空位置可能完全被车轮占满,而当此时工人3取车架时将无法得到,而工人1又无法将新加工的车架放入箱中。上述两种情况都意味着死锁。
为防止死锁的发生,箱中车架的数量不可超过N-2,车轮的数量不可超过N-1,这些限制可以用两个信号灯来表达。
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)
详细描述还应考虑对箱子单元的描述以及访问互斥问题。建议车架放在箱子的一端,车轮放在箱子的另一端,车架与车轮都采用后进先出的管理方式。
18. 一座小桥(最多只能承重两个人)横跨南北两岸,任意时刻同一方向只允许一人过桥,南侧桥段和北侧桥段较窄只能通过一人,桥中央一处宽敞,允许两个人通过或歇息。试用信号灯和PV操作写出南、北两岸过桥的同步算法。
解:桥上可能没有人,也可能有一人,也可能有两人。
(a) 两人同时过桥(b) 两人都到中间(c) 南(北)来者到北(南)段
共需要三个信号量,load用来控制桥上人数,初值为2,表示桥上最多有2人;north用来控制北段桥的使用,初值为1,用于对北段桥互斥;south用来控制南段桥的使用,初值为1,用于对南段桥互斥。
semaphore load=2;
semaphore north=1;
semaphore south=1;


tosouth(){
P(load);
P(north);
过北段桥;
到桥中间;
V(north);
P(south);
过南段桥;
到达南岸
V(south);
V(load);
}
tonorth(){
P(load);
P(south);
过南段桥;
到桥中间
V(south);
P(north);
过北段桥;
到达北岸
V(north);
V(load);
}
19.某寺庙,有小和尚、老和尚若干.庙内有一水缸,由小和尚提水入缸,供老和尚饮用。水缸可容纳 30 桶水,每次入水、取水仅为1桶,不可同时进行。水取自同一井中,水井径窄,每次只能容纳一个水桶取水。设水桶个数为5个,试用信号灯和PV操作给出老和尚和小和尚的活动。
semaphore empty=30;// 表示缸中目前还能装多少桶水,初始时能装30桶水
semaphore full=0;// 表示缸中有多少桶水,初始时缸中没有水
semaphore buckets=5;// 表示有多少只空桶可用,初始时有5只桶可用
semaphore mutex_well=1;// 用于实现对井的互斥操作
semaphore mutex_bigjar=1; // 用于实现对缸的互斥操作

young_monk(){
while(1){
P(empty);
P(buckets);
go to the well;
P(mutex_well);
get water;
V(mutex_well);
go to the temple;
P(mutex_bigjar);
pure the water into the big jar;
V(mutex_bigjar);
V(buckets);
V(full);
}
}
old_monk(){
while(){
P(full);
P(buckets);
P(mutex_bigjar);
get water;
V(mutex_bigjar);
drink water;
V(buckets);
V(empty);
}
}
20. 设系统中有5台类型相同的打印机,依次编号为1~5。 又设系统中有n个使用打印机的进程,使用前申请,使用后释放。 每个进程有一个进程标识,用于区别不同的进程。每个进程还有一个优先数,不同进程的优先数各异。当有多个进程同时申请时,按照进程优先数由高到低的次序实施分配。 试用信号灯和PV操作实现对于打印机资源的管理,即要求编写如下函数和过程:
(1) 函数 require(pid,pri): 申请一台打印机。参数pid为进程标识,其值为1到n的整数; pri为进程优先数,其值为正整数; 函数返回值为所申请到打印机的编号,其值为1到5的整数;
(2) 过程 return(prnt): 释放一台打印机。参数prnt为所释放打印机的编号,其值为1到5的整数。
解:
#define N 5
bool flag[N+1];//flag[0]表示可用打印机数,
//flag[i]表示第i号打印机的状态(1<=i<=N),0表示占用,1表示空闲
PCB *queue=NULL;//进程阻塞队列
semaphore mutex_flag=1;//用于对flag数组的互斥操作
semaphore mutex_queue=1;//用于对阻塞队列的互斥操作

process(int i,int priority){
int print;
print=require(i,priority);
use print;
return(print);
}


int require(int pid,int priority){
P(mutex_flag);
if(flag[0]>0){
flag[0]--;
for(int i=1;i<N+1;i++)
if(flag[i]==1){
flag[i]=0;
break;
}
V(mutex_flag);
return i;
}
else{
V(mutex_flag);
p(mutex_queue);
将进程pid按其优先数插入到等待队列queue中;
V(mutex_queue);
}
}


return(int print){
P(mutex_flag);
if(queue==NULL){
flag[0]++;
flag[print]=1;
V(mutex_flag);
}
else{
V(mutex_flag);
p(mutex_queue);
将print分配给queue队首进程;
queue下移;
V(mutex_queue);
}
}

21. 试用管程实现单一资源的管理。
解:
TYPE single_resource=MONITOR;
Var state: (free,used);//资源状态
q: condition;//等待队列
define require, release;
PROCEDURE require;
BEGIN
IF state=used THEN
wait(q);
state:=used;
END;
PROCEDURE release;
BEGIN
state:=free;
signal(q);
END;
BEGIN state:=free END;
22. 虽然管程是互斥进入的,但管程中定义的外部子程序必须是可再入的,试说明原因。
答:管程互斥是在变量级别的,同一管程类型可以有多个实例,而管程内部子程序只在管程类型定义时生成一套代码,为保障对不同管程变量的操作具有相同语义,管程外部子程序必须是可再入的。
23. 编写一个管程,使得调用进程能够等待若干指定时间单位(ticks).可以假定有一个硬件实时钟,每隔一个tick时间单位调用该管程一次。
解:两个外部过程:sleep用于进程等待指定时间,tick用于时钟中断记数和唤醒等待进程。
TYPE sleep_interval=MONITOR;
Var count: integer;//tick计数
q: condition;//等待队列
define sleep, tick;
PROCEDURE sleep(interval:integer);
BEGIN
count:=interval
wait(q);
END;
PROCEDURE tick;
BEGIN
count:=count-1;
IF count=0 THEN
signal(q);
END;
BEGIN END;
24. 管程与会合这两种同步机制之间的主要差别何在?
答:管程与会合都属于集中式结构化同步机制,但二者的实现机理完全不同。管程是被动性语言成分,管程本身不能占有处理机,管程外部子程序是由调用进程占有处理机执行的。会合是主动性语言成分,一个任务调用另一任务中的入口时,入口代码是由被调用任务自己占有处理机执行的。
25. 试用会合给出读写问题的解法,要求写者优先.
解:定义一个任务,包含如下四个入口:start_read,finish_read, start_write,finish_write。该问题的关键是:strat_write的入口条件不应考虑当前读者情况,当会合发生后再判断当前是否有读者,并与其finish_read会合。这里显然需要accept语句的嵌套。
task readers_and_writers is
start_read;
finish_read;
start_write;
finish_write;
end readers_and_writers;
task body readers_and_writers is
read_count,write_count:integer;
read_count:=0;
write_count:=0;
loop
select
when write_count=0 =>
accept start_read do
read_count:=read_count+1;
end start_read
or when read_count>0 =>
accept finish_read do
read_count:=read_count-1;
end finish_read;
or when write_count=0 =>//也许当前有读者
accept start_write do
while read_count>0 do//等待读者读完
accept finish_read do
read_count:=read_count-1
end finish_read
end while
write_count:=write_count+1;
end start_write
or when write_count>0 =>
accept finish_write do
write_count:=write_count-1;
end finish_write
end select;
end loop;
end readers_and_writers;
26. 关于读者/写者问题,有人给出如下改进解法:
semaphore r_w_w, mutex, s; (初值均为1)
int count; (初值为0)
读者活动:
P(s);
P(mutex);
count++;
if (count= =1)
P(r_w_w);
V(mutex);
V(s);
{读操作}
P(mutex);
count--;
If (count= =0)
V(r_w_w);
V(mutex);

写者活动:
P(s);
P(r_w_w);
{写操作}
V(r_w_w);
V(s);

分析上述改进算法的调度效果。
答:由于s以及读者和写者对s的操作,读者和写者都不会无限等待,因而算法不会出现饿死现象,是一个公平的解法
体验新版博客
上一篇:
五、 死锁习题及解答:
下一篇:
三、 处理机调度习题及解答:
分享 分享 | 评论 (0) | 阅读 (68) | 固定链接 | 发表于 22:07
提示:“固定链接”为您显示此篇文章的固定不变链接,如果您有还有疑问请点击帮助
链接地址:http://jymjl1009.blog.sohu.com/112809495.html 复制此地址

评论 同步问题 想第一时间抢沙发么?


由于最近广告泛滥,暂只允许登录用户对此文评论。登录

四、 同步与互斥习题及解答:
1. 何谓与时间有关的错误? 举例说明之。
答:并发进程的执行实际上是进程活动的某种交叉,某些交叉次序可能得到错误结果。由于具体交叉的形成与进程的推进速度有关,而速度是时间的函数,因而将这种错误称为与时间有关的错误。
例如,两个并发进程的程序如下:
int n=0;
main( ){
创建进程A;
创建进程B;
};

A( ){
while(1){
n++;
}
};
B( ){
while(1){
睡眠一段时间;
printf(“%d”,n);
n=0; }
};
假设进程A被部署在公园入口的终端上,用来记录一段时间内进入公园的人数,进程B被部署在公园的控制中心,用来输出一段时间内进入公园的总人数。进程A和进程B共享全局变量n,n表示记录下的人数。如果在进程B执行完打印语句后被进程A打断,进程A执行了若干次变量自增语句,之后进程B接着执行清0语句,那么进程A对n的累加丢失了,相当于进程B被打断的这段时间内进入公园的人没有被记录下来。发生与时间有关的错误。
2. 有人说,假设两个进程之间没有共享内存,则二者之间没有公共变量,这种说法准确吗? 说明原因。
答:如果只从用户空间考虑,这种说法是正确的。但从操作系统的角度来说并不准确。两个没有公共内存的用户进程可能同时(宏观)进入操作系统,并访问操作系统空间中的公共变量。
3.何谓忙式等待? 是否还有其它方式的等待? 比较它们之间的联系和差别。
答:不进入等待状态的等待称为忙式等待。另一种等待方式是阻塞式等待,进程得不到共享资源时将进入阻塞状态,让出CPU给其他进程使用。忙等待和阻塞式等待的相同之处在于进程都不具备继续向前推进的条件,不同之处在于处于忙等待的进程不主动放弃CPU,尽管CPU可能被剥夺,因而是低效的;而处于阻塞状态的进程主动放弃CPU,因而是高效的。
4.下列进程互斥方法哪些存在忙式等待问题?
(1)软件: 面包店算法(2) 硬件: TS指令(3) 关中断指令
答:(1)、(2)存在忙等待问题。
5.为何开关中断进程互斥方法仅在单CPU系统中是有效的?
答:关中断方法不适用于多CPU系统,因为关中断只能保证CPU不由一个进程切换到另外一个进程,从而防止多个进程并发地进入公共临界区域。但即使关中断后,不同进程仍可以在不同CPU上并行执行关于同一组共享变量的临界区代码.
6.在多处理机系统中,软件互斥方法是否有效?为什么?
  答:依然有效。多处理机并行与单处理并发之间的差别在于程序交叉的粒度,单处理机机环境中进程交叉发生在指令之间,多处理机环境中进程交叉发生在指令周期之间。由于纯软件互斥算法并不依赖特殊的硬件指令(如test_and_set),指令之间的交叉与指令周期之间的交叉结果相同。
7.试分析临界区域的大小与系统并发性之间的关系。
答:关于同一组变量的临界区域是不能并发执行的代码,临界区越大,并发性越差,因而编写并发程序应尽量缩小临界区域范围。
8.设CR1是关于一组共享变量SV1的临界区域,CR2是关于另外一组共享变量SV2的临界区域,当进程P1进入CR1时,进程P2是否可以进入CR2? 为什么?
答:可以。因为互斥是在变量级别上的,多个进程同时进入关于不同变量的临界区不会引起与时间有关的错误。
9.Lamport面包店互斥算法是否会出现饿死情况?
  不会,该算法是公平的。假定系统中共有n个进程,每个想要进入临界区域的进程(线程)在最坏的情况下需要等待其它n-1个进程进入并离开临界区域之后即可获得进入临界区域的机会,因而存在(忙式)等待的上界。
10.试用信号灯和PV操作实现临界区语句:
region <共享变量> do <语句>
变量类型<共享变量>
答:
semaphore s=1;
P(s);
<语句>
V(s);
11. 由V操作唤醒的进程是否一定能够直接进入运行状态? 举例说明之。
答:否。一般来说,唤醒是将进程状态由等待状态变成就绪状态,而就绪进程何时获得处理机则是由系统的处理机调度策略确定的。如果采用抢占式优先级调度算法,并且被唤醒的进程是当前系统中优先级最高的进程,那么该进程将被调度执行,其状态变成运行态。如果该进程不是系统中优先级最高的进程或系统采用其它调度算法,那么该进程不会被调度执行,其状态将维持在就绪态。
12. 设S1和S2为两个信号灯变量,下列八组P、V操作哪些可以同时进行? 哪些不能同时进行? 为什么?
(1)P(S1),P(S2) (2)P(S1),V(S2)
(3)V(S1),P(S2) (4)V(S1),V(S2)
(5)P(S1),P(S1) (6)P(S2),V(S2)
(7)V(S1),P(S1) (8)V(S2),V(S2)
答:能同时进行的包括:(1)、(2)、(3)、(4)。这些操作涉及不同信号灯变量,属于关于不同组共享变量的临界区。不能同时进行的包括:(5)、(6)、(7)、(8)。这些操作涉及相同的信号灯变量,属于关于同一组共享变量的临界区。
13. 对于生产者—消费者问题,假设缓冲区是无界的,试用信号灯与PV操作给出解法。
答:由于是无界缓冲区,所以生产者不会因得不到缓冲区而被阻塞,不需要对空缓冲区进行管理,可以去掉在有界缓冲区中用来管理空缓冲区的信号量及其PV操作。
semaphore mutex_in=1;
semaphore mutex_out=1;
semaphore empty=0;
int in=0,out=0;

生产者活动:
while(1){
produce next product;
P(mutex_in);
add the product to buffer[in];
in++;
v(mutex_in);
V(empty);
}
消费者活动:
while(1){
P(empty);
P(mutex_out);
take the product from buffer[out];
out++;
V(mutex_out);
}
14. 设有一个可以装A、B两种物品的仓库,其容量无限大,但要求仓库中A、B两种物品的数量满足下述不等式:
-M≤A物品数量-B物品数量≤N
其中M和N为正整数。 试用信号灯和PV操作描述A、B两种物品的入库过程。
答:已知条件 -M≤A物品数量-B物品数量≤N 可以拆成两个不等式,即
A物品数量-B物品数量≤N
B物品数量-A物品数量≤M
这两个不等式的含义是:仓库中A物品可以比B物品多,但不能超过N个;B物品可以比A物品多,但不能超过M个。
semaphore a=n;
semaphore b=m;
void main(){
createprocess(A,…);
createprocess(B,…);
}
A物品入库:
void A(){
while(1){
P(a);
A物品入库;
V(b);
}
}
B物品入库:
void B(){
while(1){
P(b);
B物品入库;
V(a);
}
}
15. 试用信号灯与PV操作实现司机与售票员之间的同步问题。设公共汽车上有一个司机和一个售票员,其活动如下图
所示。

为了安全起见,显然要求: (1)关车门后方能启动车辆;(2)到站停车后方能开车门。亦即“启动车辆”这一活动应当在“关车门”这一活动之后,“开车门”这一活动应当在“到站停车”这一活动之后。
解:如果进程P2尚未推进到②处时,进程P1已经推进到①处,则P1应等待直到P2推进到②处为止;同样,如果进程P1尚未推进到③处时,进程P2已经推进到④处,则P2应等待直到P1推进到③处为止。如果进程P1在①处发生了等待,则当进程P2执行到②处时应将P1唤醒;同样,如果进程P2在④处发生了等待,则当进程P2执行到③处时应将P1唤醒。用信号量和P、V操作解决这一问题,需要定义两个信号量,一个信号量start表示是否允许司机启动车辆,另一个信号量open表示是否允许售票员开车门。初始状态是车停在始发站,车门开着,等待乘客上车。因此,两个信号量的初值都是0。
semaphore start=0;
semaphore open=0;


司机的活动:
P1: do{
P(start);
启动车辆;
正常行车;
到站停车;
V(open);
}while (1);

售票员的活动:
P2: do{
关车门;
V(start);
售票;
P(open);
开车门;
}while (1);
16. 设有A、B、C三组进程,它们互斥地使用某一独占型资源R,使用前申请,使用后释放。资源分配原则如下:
(1) 当只有一组申请进程时,该组申请进程依次获得R;
(2) 当有两组申请进程时,各组申请进程交替获得R,组内申请进程依次获得R;
(3) 当有三组申请进程时,各组申请进程轮流获得R,组内申请进程依次获得R。
试用信号灯和PV操作分别给出各组进程的申请活动程序段和释放活动程序段。
解:
int free=1;//设备状态标志
semaphore mutex=1;
semaphore qa=qb=qc=0; //各组等待队列
int counta=countb=countc=0;//等待队列长度
A组申请:
P(mutex);
if(free==1){
free=0;
V(mutex);
}
else{
counta++;
V(mutex);
P(qa);
}
A组释放:
P(mutex);
if(countb>0){
countb--;
V(qb);
}else{
if(countc>0){
countc--;
V(qc);
}else{
if(counta>0){
counta--
V(qa);
}else{
free=1;
}
}
}
}
A组进程活动可以给出B组和C组进程活动。
17. 设自行车生产线上有一只箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮; 又设有三个工人,其活动分别为:
工人1活动:
do {
加工一个车架;
车架放入箱中;
}while(1)
工人2活动:
do {
加工一个车轮;
车轮放入箱中;
}while(1)
工人3活动:
do {
箱中取一车架;
箱中取二车轮;
组装为一台车;
}while(1)
试分别用信号灯与PV操作、管程、会合实现三个工人的合作,要求解中不含死锁。
解:用信号灯与PV操作实现三个工人的合作,管程与会合解法可仿照给出。
首先不考虑死锁问题,工人1与工人3、工人2与工人3构成生产者与消费者关系,这两对生产/消费关系通过共同的缓冲区相联系。从资源的角度来看,箱子中的空位置相当于工人1和工人2的资源,而车架和车轮相当于工人3的资源。定义三个信号灯如下:
semaphore empty=N;//空位置
semaphore wheel=0;//车轮
semaphore frame=0;//车架
三位工人的活动分别为:
工人1活动:
do {
加工一个车架;
P(empty);
车架放入箱中;
V(frame);
}while(1)
工人2活动:
do {
加工一个车轮;
P(empty);
车轮放入箱中;
V(wheel);
}while(1)
工人3活动:
do {
P(frame);
箱中取一车架;
V(empty);
P(wheel);
P(wheel);
箱中取二车轮;
V(empty);
V(empty);
组装为一台车;
}while(1)
分析上述解法易见,当工人1推进速度较快时,箱中空位置可能完全被车架占满或只留有一个存放车轮的位置,而当此时工人3同时取2个车轮时将无法得到,而工人2又无法将新加工的车轮放入箱中;当工人2推进速度较快时,箱中空位置可能完全被车轮占满,而当此时工人3取车架时将无法得到,而工人1又无法将新加工的车架放入箱中。上述两种情况都意味着死锁。
为防止死锁的发生,箱中车架的数量不可超过N-2,车轮的数量不可超过N-1,这些限制可以用两个信号灯来表达。
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)
详细描述还应考虑对箱子单元的描述以及访问互斥问题。建议车架放在箱子的一端,车轮放在箱子的另一端,车架与车轮都采用后进先出的管理方式。
18. 一座小桥(最多只能承重两个人)横跨南北两岸,任意时刻同一方向只允许一人过桥,南侧桥段和北侧桥段较窄只能通过一人,桥中央一处宽敞,允许两个人通过或歇息。试用信号灯和PV操作写出南、北两岸过桥的同步算法。
解:桥上可能没有人,也可能有一人,也可能有两人。
(a) 两人同时过桥(b) 两人都到中间(c) 南(北)来者到北(南)段
共需要三个信号量,load用来控制桥上人数,初值为2,表示桥上最多有2人;north用来控制北段桥的使用,初值为1,用于对北段桥互斥;south用来控制南段桥的使用,初值为1,用于对南段桥互斥。
semaphore load=2;
semaphore north=1;
semaphore south=1;


tosouth(){
P(load);
P(north);
过北段桥;
到桥中间;
V(north);
P(south);
过南段桥;
到达南岸
V(south);
V(load);
}
tonorth(){
P(load);
P(south);
过南段桥;
到桥中间
V(south);
P(north);
过北段桥;
到达北岸
V(north);
V(load);
}
19.某寺庙,有小和尚、老和尚若干.庙内有一水缸,由小和尚提水入缸,供老和尚饮用。水缸可容纳 30 桶水,每次入水、取水仅为1桶,不可同时进行。水取自同一井中,水井径窄,每次只能容纳一个水桶取水。设水桶个数为5个,试用信号灯和PV操作给出老和尚和小和尚的活动。
semaphore empty=30;// 表示缸中目前还能装多少桶水,初始时能装30桶水
semaphore full=0;// 表示缸中有多少桶水,初始时缸中没有水
semaphore buckets=5;// 表示有多少只空桶可用,初始时有5只桶可用
semaphore mutex_well=1;// 用于实现对井的互斥操作
semaphore mutex_bigjar=1; // 用于实现对缸的互斥操作

young_monk(){
while(1){
P(empty);
P(buckets);
go to the well;
P(mutex_well);
get water;
V(mutex_well);
go to the temple;
P(mutex_bigjar);
pure the water into the big jar;
V(mutex_bigjar);
V(buckets);
V(full);
}
}
old_monk(){
while(){
P(full);
P(buckets);
P(mutex_bigjar);
get water;
V(mutex_bigjar);
drink water;
V(buckets);
V(empty);
}
}
20. 设系统中有5台类型相同的打印机,依次编号为1~5。 又设系统中有n个使用打印机的进程,使用前申请,使用后释放。 每个进程有一个进程标识,用于区别不同的进程。每个进程还有一个优先数,不同进程的优先数各异。当有多个进程同时申请时,按照进程优先数由高到低的次序实施分配。 试用信号灯和PV操作实现对于打印机资源的管理,即要求编写如下函数和过程:
(1) 函数 require(pid,pri): 申请一台打印机。参数pid为进程标识,其值为1到n的整数; pri为进程优先数,其值为正整数; 函数返回值为所申请到打印机的编号,其值为1到5的整数;
(2) 过程 return(prnt): 释放一台打印机。参数prnt为所释放打印机的编号,其值为1到5的整数。
解:
#define N 5
bool flag[N+1];//flag[0]表示可用打印机数,
//flag[i]表示第i号打印机的状态(1<=i<=N),0表示占用,1表示空闲
PCB *queue=NULL;//进程阻塞队列
semaphore mutex_flag=1;//用于对flag数组的互斥操作
semaphore mutex_queue=1;//用于对阻塞队列的互斥操作

process(int i,int priority){
int print;
print=require(i,priority);
use print;
return(print);
}


int require(int pid,int priority){
P(mutex_flag);
if(flag[0]>0){
flag[0]--;
for(int i=1;i<N+1;i++)
if(flag[i]==1){
flag[i]=0;
break;
}
V(mutex_flag);
return i;
}
else{
V(mutex_flag);
p(mutex_queue);
将进程pid按其优先数插入到等待队列queue中;
V(mutex_queue);
}
}


return(int print){
P(mutex_flag);
if(queue==NULL){
flag[0]++;
flag[print]=1;
V(mutex_flag);
}
else{
V(mutex_flag);
p(mutex_queue);
将print分配给queue队首进程;
queue下移;
V(mutex_queue);
}
}

21. 试用管程实现单一资源的管理。
解:
TYPE single_resource=MONITOR;
Var state: (free,used);//资源状态
q: condition;//等待队列
define require, release;
PROCEDURE require;
BEGIN
IF state=used THEN
wait(q);
state:=used;
END;
PROCEDURE release;
BEGIN
state:=free;
signal(q);
END;
BEGIN state:=free END;
22. 虽然管程是互斥进入的,但管程中定义的外部子程序必须是可再入的,试说明原因。
答:管程互斥是在变量级别的,同一管程类型可以有多个实例,而管程内部子程序只在管程类型定义时生成一套代码,为保障对不同管程变量的操作具有相同语义,管程外部子程序必须是可再入的。
23. 编写一个管程,使得调用进程能够等待若干指定时间单位(ticks).可以假定有一个硬件实时钟,每隔一个tick时间单位调用该管程一次。
解:两个外部过程:sleep用于进程等待指定时间,tick用于时钟中断记数和唤醒等待进程。
TYPE sleep_interval=MONITOR;
Var count: integer;//tick计数
q: condition;//等待队列
define sleep, tick;
PROCEDURE sleep(interval:integer);
BEGIN
count:=interval
wait(q);
END;
PROCEDURE tick;
BEGIN
count:=count-1;
IF count=0 THEN
signal(q);
END;
BEGIN END;
24. 管程与会合这两种同步机制之间的主要差别何在?
答:管程与会合都属于集中式结构化同步机制,但二者的实现机理完全不同。管程是被动性语言成分,管程本身不能占有处理机,管程外部子程序是由调用进程占有处理机执行的。会合是主动性语言成分,一个任务调用另一任务中的入口时,入口代码是由被调用任务自己占有处理机执行的。
25. 试用会合给出读写问题的解法,要求写者优先.
解:定义一个任务,包含如下四个入口:start_read,finish_read, start_write,finish_write。该问题的关键是:strat_write的入口条件不应考虑当前读者情况,当会合发生后再判断当前是否有读者,并与其finish_read会合。这里显然需要accept语句的嵌套。
task readers_and_writers is
start_read;
finish_read;
start_write;
finish_write;
end readers_and_writers;
task body readers_and_writers is
read_count,write_count:integer;
read_count:=0;
write_count:=0;
loop
select
when write_count=0 =>
accept start_read do
read_count:=read_count+1;
end start_read
or when read_count>0 =>
accept finish_read do
read_count:=read_count-1;
end finish_read;
or when write_count=0 =>//也许当前有读者
accept start_write do
while read_count>0 do//等待读者读完
accept finish_read do
read_count:=read_count-1
end finish_read
end while
write_count:=write_count+1;
end start_write
or when write_count>0 =>
accept finish_write do
write_count:=write_count-1;
end finish_write
end select;
end loop;
end readers_and_writers;
26. 关于读者/写者问题,有人给出如下改进解法:
semaphore r_w_w, mutex, s; (初值均为1)
int count; (初值为0)
读者活动:
P(s);
P(mutex);
count++;
if (count= =1)
P(r_w_w);
V(mutex);
V(s);
{读操作}
P(mutex);
count--;
If (count= =0)
V(r_w_w);
V(mutex);

写者活动:
P(s);
P(r_w_w);
{写操作}
V(r_w_w);
V(s);

分析上述改进算法的调度效果。
答:由于s以及读者和写者对s的操作,读者和写者都不会无限等待,因而算法不会出现饿死现象,是一个公平的解法

我的更多文章

下载客户端阅读体验更佳

APP专享