计算机操作系统从第二章开始内容会变得异常多,还是希望能够帮助到大家,在这一章阿婆主还会把书上的典型的PV操作题给打上来,给大家用作参考,如果有问题的地方,还请大家在文章下方留言,我好更正,或者你们有更好的PV操作的解法,也欢迎大家在文章下方留言讨论,同学习,共进步~
目录(检索你需要知道的知识点)
第二章操作系统的基础知识点
2.1.1 在操作系统中为什么要引入进程概念?它会产生什么样的影响?
2.1.2 试比较进程与程序的异同。
2.1.3 某系统的进程状态转换图如下图所示:请:
(1)说明引起各种状态转换的典型事件。
(2)分析状态转换1,2,3,4是否可立即引起其他的状态转换。
2.1.4 PCB的作用是什么?为什么说PCB是进程存在的唯一标志?
2.2.1 为什么诸进程对临界资源的访问必须互斥?
2.2.2 如何保证诸进程互斥地访问临界资源?
2.2.3 何谓“忙等”?它有什么缺点?
2.2.4 进程之间存在着哪几种制约关系?各是什么原因引起的?下列活动分别属于哪种制约关系?
2.2.5 我们为某临界区设置一把锁W,当W=1时,表示关锁;W=0时表示锁已打开。试写出开锁和关锁原语,并利用它们实现互斥。
2.2.6 下述算法是解决两进程互斥访问临界区问题的一种方法。试从“互斥”、“空闲让进”、“有限等待”等三方面讨论它的正确性。如果它是正确的,则证明之;如果它不正确,请说明理由。
2.3.1 如下图所示,有一计算进程和打印进程,它们共享一个单缓冲区,计算进程不断地计算出一个整型结果并将它放入单缓冲区中,打印进程则负责从单缓冲区取出每一个结果进行打印,请用信号量来实现它们的同步关系。
2.4.1 在生产者--消费者问题中,如果将两个wait操作,即wait(full)和wait(mutex)互换位置,或者wait(empty)和wait(mutex)互换位置,其后果如何?如果将两个signal操作互换位置,即signal(full)和signal(mutex)互换位置,或者signal(empty)和 signal(mutex)互换位置,其后果又如何?
2.4.2 有三个进程PA、PB和PC协作解决文件打印问题。PA将文件记录从磁盘读入内存的缓冲区1,每执行一次读一个记录;PB将缓冲区1的内容复制到缓冲区2中,每执行一次复制一个记录;PC将缓冲区2的内容打印出来,每执行一次打印一个记录。缓冲区的大小与记录大小一样。请用信号量来保证文件的正确打印。
2.4.3 进程A1、A2、......、An1通过m个缓冲区向进程B1、B2、......、Bn2不断地发送消息。发送和接收工作遵循如下规则:
(1)每个发送进程一次发送一个消息,写入一个缓冲区,缓冲区大小和消息长度相同;
(2)对每一个消息,B1、B2、.......、Bn2都需要各接收一次,读入自己的数据区内;
(3)m个缓冲区都满时,发送进程等待;没有可读的消息时,接收进程等待。
试用wait、signal操作描述它们的同步关系。
2.4.4 桌上有个能盛得下五个水果的空盘子。爸爸不停地向盘中放苹果或桔子,儿子不停地从盘中取出桔子享用,女儿不停地从盘中取出苹果享用。规定三人不能同时从盘子中存放水果。试用信号量实现爸爸、儿子和女儿这三个循环进程之间的同步。
2.4.5 设有两个生产者进程A、B和一个销售者进程C,他们共享一个无限大的仓库,生产者每次循环生产一个产品,然后入库供销售者销售;销售者每次循环从仓库中取出一个产品进行销售。如果不允许同时入库,也不允许边入库边出库;而且要求生产A产品和B产品的件数满足以下关系:-n<=A的件数-B的件数<=m,其中n、m是正整数,但对仓库中A产品和B产品的件数无上述要求。请用信号量机制写出A、B、C三个进程的工作流程。
2.4.6 试用记录型信号量写出一个不会死锁的哲学家进餐问题的算法。
2.4.7 嗜睡的理发师问题:一个理发店由一个有N张沙发的等候室和一个放有一张理发椅的理发室组成。没有顾客要理发时,理发师便去睡觉。当一个顾客走进理发店时,如果所有的沙发都已被占用,他便离开理发店;否则,如果理发师正在为其他顾客理发,则该顾客就找一张空沙发坐下等待;如果理发师因无顾客正在睡觉,则由新到的顾客唤醒理发师为其理发。在理发完成后,顾客必须付费,直到理发师收费后才能离开理发店。试用信号量实现这一同步问题。
2.4.8 请给出一个写者优先的“读者--写者”问题的算法描述。
2.4.9 请用信号量解决以下的“过独木桥”问题:同一方向的行人可连续过桥,当某一方向有人过桥时,另一方向的行人必须等待;当某一方向无人过桥时,另一方向的行人可以过桥。
2.4.10 有一间酒吧里有3个音乐爱好者队列,第1队的音乐爱好者只有随身听,第2队的音乐爱好者只有音乐磁带,第3队的音乐爱好者只有电池。而要听音乐就必须随身听、音乐磁带和电池这三种物品俱全。酒吧老板一次出售这三种物品种的任意两种。当一名音乐爱好者得到这三种物品并听完一首乐曲后,酒吧老板才能再一次出售这三种物品种的任意两种,于是第2名音乐爱好者得到这三种物品,并开始听乐曲。全部买卖就这样进行下去。试用信号量实现他们的同步关系。
2.5.1 消息缓冲队列通信机制应具有哪几方面的功能?
2.5.2 试比较直接通信方式和间接通信方式。
2.6.1 试从调度性、并发性、拥有资源、独立性、系统开销以及对多处理机的支持等方面,对进程和线程进行比较。
2.6.2 什么是内核支持线程和用户级线程?并对它们进行比较。
第二章操作系统的基础知识点
2.1 进程基本概念中的典型问题分析
2.1.1 在操作系统中为什么要引入进程概念?它会产生什么样的影响?
答:在操作系统中引入进程概念,是为了实现多个程序的并发执行。传统的程序与其他程序并发执行时,其执行时结果不可再现,因此,传统的程序不能与其他程序并发执行,只有在为之创建进程后,才能与其他程序(进程)并发执行。这是因为并发执行的程序是“停停走走”地执行,只有在为它创建进程后,在它停下时,方能将其现场信息保存在它的PCB中,待下次被调度执行时,再从PCB中恢复CPU现场而继续执行,而传统的程序却无法满足上述要求。
建立进程所带来的好处是多个程序能并发执行,这极大地提高了资源利用率和系统吞吐量。但管理进程也需要付出一定的代价,包括进程控制块及协调各运行的机狗所占用的内存空间开销,以及为进行进程间的切换、同步及通信等所付出的时间开销。
2.1.2 试比较进程与程序的异同。
答:进程和程序是紧密相关而又完全不同的两个概念。
(1)每个进程实体中包含了程序段和数据段这两个部分,因此说进程与程序是紧密相关的。但从结构上看,进程实体中除了程序段和数据段外,还必须包含一个数据结构,即进程控制块PCB。
(2)进程是程序第一次执行过程,因此是动态的;动态性还表现在进程由创建而产生、由调度而执行、由撤销而消亡,即它具有一定的生命周期。而程序则只是一组指令的有序集合,并可永久地存放在某种介质上,其本身不具有运动的含义,因此是静态的。
(3)多个进程实体可同时存放在内存中并发地执行,这正是引入进程的目的。而程序(在没有为它创建进程时)的并发执行具有不可再现性,因此程序不能正确地并发执行。
(4)进程是一个能够独立运行、独立分配资源和独立接受调度的基本单位。而程序(在没有为它创建进程时)因其不具有PCB,故是不可能在多道程序环境下独立运行的。
(5)进程与程序不一一对应。同一个程序的多次运行,将形成多个不同的进程;同一个程序的一次执行也可以产生多个进程(如UNIX中通过fork调用产生子进程);而一个进程在其生命周期的不同时候可以执行不同的程序(如UNIX中通过exec调用更换进程的执行代码)。
2.1.3 某系统的进程状态转换图如下图所示:
请:
(1)说明引起各种状态转换的典型事件。
(2)分析状态转换1,2,3,4是否可立即引起其他的状态转换。
答:
(1)引起各种状态转换的典型事件如下表所示:
状态转换 | 引起转换的典型事件 |
---|---|
转换-1 | CPU调度 |
转换-2 | 执行进程的时间片用完,或被其他优先权更高的进程抢占CPU |
转换-3 | 等待某种事件(如I/O的完成,或被他人占用的临界资源变为可用状态) |
转换-4 | 进程所等待的事件发生(如I/O完成,或所等待的临界资源变为可用状态) |
(2)状态转换-1不会立即引起其他状态转换。
状态转换-2必然立即引发状态转换-1。状态转换-2发生后,进程调度程序必然要选出一个新的就绪进程投入运行,该新进程可能是其他进程,也可能是刚从执行状态转换成就绪状态的那个进程。
状态转换-3可能立即引发状态转换-1。状态转换-3发生后,若就绪队列非空,则进程调度程序将选出一个就绪进程投入执行。
状态转换-4可能引发状态转换-1。状态转换-4发生后,若CPU空闲,并且没有其他进程竞争CPU,则该进程将被立即调度。另外,状态转换-4还可能同时引发状态转换-1和-2.若系统采用抢占调度方式,而新就绪的进程具备抢占CPU的条件(如其优先权很高),则它可立即得到CPU转换成执行状态,而原来正在执行的进程则转换成就绪状态。
2.1.4 PCB的作用是什么?为什么说PCB是进程存在的唯一标志?
答:进程控制块是操作系统用来描述和管理进程的数据结构,其作用是使一个在多道程序环境下、不能独立运行的程序,成为一个能独立运行的基本单位,即一个能与其他进程并发执行的进程。
在创建进程时,系统将为它配置一个PCB,在进行进程调度时,系统将根据PCB中的状态和优先级等信息来选择新进程,然后将老进程的现场信息保存到它的PCB中,再根据新进程PCB中所保存的处理机状态信息来恢复运行的现场;执行中的进程,如果需要访问文件或者需要与合作进程实现同步或通信,也都需要访问PCB;当进程因某种原因而暂停执行时,也必须将断点的现场信息保存到它的PCB中;当进程结束时,系统将回收它的PCB。可见,在进程的整个生命期中,系统总是通过其PCB对进程进行控制和管理,亦即,系统是根据其PCB而不是任何别的什么而感知到某进程的存在,所以说,PCB是进程存在的唯一标志。
2.2 进程同步基本概念中的典型问题分析
2.2.1 为什么诸进程对临界资源的访问必须互斥?
答:临界资源本身的特性决定了它们只能被诸进程互斥地访问,如果并发执行的多个进程同时访问临界资源,将会造成系统的混乱或程序执行结果的不确定性,这样,用户得到的便可能时不希望得到的、或者是不正确的处理结果。如多个用户同时使用同一台打印机,将使他们的输出结果交织在一起,而难于区分;又如两个用户使用程序段:
mov ax,(counter)
inc ax
mov (counter),ax
对初值为0的共享变量counter进行计数(加1)操作,则最终counter的值可能是正确的结果2,也可能是错误的结果1,即计算结果出现了不确定性。所以,诸进程对临界资源的访问必须互斥地进行。
2.2.2 如何保证诸进程互斥地访问临界资源?
答:为了互斥地访问临界资源,系统必须保证进程互斥地进入临界区。为此,必须在临界区前增加一段称作进入区的代码,以检查是否有其他进程已进入临界区使用临界资源,若有,则进程必须等待;否则,允许进程进入临界区,同时设置标志表示有进程正在临界区内。同样,在临界区后必须增加一段称作退出区的代码,用于将已有进程进入临界区访问临界资源的标志为无进程进入临界区使用临界资源。进入区、退出区具体可用多种同步机制实现,如锁、信号量机制等。
2.2.3 何谓“忙等”?它有什么缺点?
答:所谓“忙等”是指“不让权”的等待,即进程因某事件的发生而无法继续执行时,它仍占有CPU,并通过不断地执行循环测试指令来等待该事件的完成。
“忙等”的主要缺点是浪费CPU的时间,另外,它还可能引起预料不到的后果。例如考虑某个采取高优先权优先调度原则的系统,目前有两个进程A和B共享某个临界资源,A的优先权较高,B的优先权较低,且B已处于临界区内,而A欲进入自己的临界区,则A、B都不可能继续向前推进,陷入“死等”状态。
2.2.4 进程之间存在着哪几种制约关系?各是什么原因引起的?下列活动分别属于哪种制约关系?
(1)若干同学去图书馆借书;
(2)两队举行篮球比赛;
(3)流水线生产的各道工序;
(4)商品生产和社会消费。
答:进程之间存在着直接制约和间接制约这两种制约关系,其中直接制约(同步)是由于进程间的相互合作而引起的;而间接制约(互斥)则是由于进程间共享临界资源而引起的。
(1)若干同学去图书馆借书是间接制约,其中书是临界资源;
(2)两队举行篮球比赛是间接制约,其中篮球是临界资源;
(3)流水线生产的各道工序是直接制约,各道工序间需要相互合作,每道工序的开始都依赖于前一道工序的完成;
(4)商品生产和社会消费是直接制约,两者也需要相互合作;商品生产出来后才可以被消费;商品被消费后才需要再生产。
2.2.5 我们为某临界区设置一把锁W,当W=1时,表示关锁;W=0时表示锁已打开。试写出开锁和关锁原语,并利用它们实现互斥。
分析:在用锁来实现互斥时,必须为每个临界资源设置一把锁W,值得注意的是,锁W只能有开或关两种状态,相应地W只能取0或1两个值。进行关锁操作时,若W处于开的状态,则表示相应的临界资源空闲,进程只需将锁的状态置为关,便可直接进入临界区;否则,若W已处于关状态,则表示其他进程正在使用临界资源,故执行关锁操作的进程必须等待。进行开锁操作时,则必须将锁的状态置为开状态,以允许其他进程使用临界资源。
答:相应的关锁原语lock(W)和开锁原语unlock(W)可描述为:
lock(W):while(W==1);//do no-op
W=1;
unlock(W):W=0;
在利用关锁原语和开锁原语实现进程互斥时,可将临界区CS放在其间,即:
lock(W;
CS;
unlock(W);
2.2.6 下述算法是解决两进程互斥访问临界区问题的一种方法。试从“互斥”、“空闲让进”、“有限等待”等三方面讨论它的正确性。如果它是正确的,则证明之;如果它不正确,请说明理由。
int c1=c2=1;
p1(){
while(1){
remain section1;
do{
c1=1-c2;
}while(c2==0);
Critical section;
c1=1;
}
}
p2(){
while(1){
remain section2;
do{
c2=1-c1;
}while(c1==0);
Critical section;
c2=1;
}
}
main(){
cobegin
p1();
p2();
coend
}
分析:在通过对共享变量的测试来实现进程互斥时,必须注意共享变量本身也应当是临界资源,如果多个进程对它们进行同时共享,则可能会导致程序互斥算法的失败。在做这类题目时,可将检查的重点放在将条件测试指令和前面(或后面)对测试指令中所用的共享变量的修改操作相分割的情况下,该变量又刚好被其他进程修改的时候。
答:本题中,p1、p2通过共享变量c1和c2来达到资源互斥使用的目的,其中,c1=1表示p1不在临界区内,c2=1表示p2不在临界区内。通过检查可知:
(1)该算法不能保证互斥访问临界区。
a、由于c1、c2的初值都为1,若p1先获得CPU并申请进入临界区,则它可以进入临界区。在p1进入临界区后,c1=0,c2=1;
b、此时若进行进程调度并由p2获得CPU,而p2也试图进入临界区,执行完c2=1-c1后,c1=0,c2=1;
c、此时若又进行CPU调度,并且p1重新获得CPU,并在退出临界区后执行c1=1,则c1=1,c2=1;
d、若再进行CPU调度,并且由p2获得CPU,因c1=1,p2进入临界区,而此时c1=1,c2=1;
e、若再进行CPU调度并由p1获得CPU,当p1再申请进入临界区时,由于c2=1,p1将顺利进入临界区。可见,在这种情况下,p1和p2将同时进入临界区。
(2)该算法能保证空闲让进。因为,c1和c2的初值均为1,而c1只有在p1申请进入自己的临界区时才可能变为0,一旦p1退出临界区,它的值又将被置为1;同样,c2只有在p2申请进入自己的临界区时才可能变为0,一旦p2退出临界区,它的值又将被置为1。所以,当临界资源空闲时,不管它是否曾经被使用过,c1和c2的值均为1;此时,若p1进程申请进入自己的临界区,则先执行c1=1-c2将c1置为0,并因c2==0条件不成立而结束循环测试,随后进入自己的临界区;对p2进程,情况也是如此。
(3)在该算法中,若一进程在临界区内执行,则另一进程将处于“忙等”状态。因此,在某些特殊的情况下,还可能不能保证“有限等待”。
2.3 信号量机制及应用中的典型问题分析
2.3.1 如下图所示,有一计算进程和打印进程,它们共享一个单缓冲区,计算进程不断地计算出一个整型结果并将它放入单缓冲区中,打印进程则负责从单缓冲区取出每一个结果进行打印,请用信号量来实现它们的同步关系。
分析1:可从临界资源的角度来思考,先找临界资源,并为每种临界资源设置信号量,在访问临界资源之前加wait操作来申请资源,访问完临界资源后加signal操作来释放临界资源。本题中有两类临界资源,第一类时计算进程争用的空闲缓冲区,初始状态下有一个空闲缓冲区可供使用,故可为它设置初值为1的信号量empty;第二类时打印进程争用的已放入缓冲中的打印结果,初始状态下缓冲中无结果可供打印,故可为它设置初值为0的信号量full。
答1:具体的同步算法可描述为:
semaphore full=0,empty=1;
int buffer;
cp(){
int nextc;
while(1){
compute the next number in nextc;
wait(empty);
buffer=nextc;
signal(full);
}
}
pp(){
int nextp;
while(1){
wait(full);
nextp=buffer;
signal(empty);
print the number in nextp;
}
}
main(){
cobegin
cp();
pp();
coend
}
其实,本题是一个n=1的生产者--消费者问题,与常规的生产者--消费者问题的算法比较一下,可以发现:单缓冲的情况下,缓冲区只需要简单变量来描述,而不必再用数组;另外,也不需要in(out)指针来指示产品放到(取自)哪个缓冲区,而且,由于此时生产者,消费者不可能同时访问缓冲区,所以原来的mutex信号量也不再需要。
分析2:还可以从同步的角度来思考,对某种同步关系,如进程A在某处必须等待进程B完成某个动作D后才能继续执行,可为它设置一初值为0的信号量,并在A需要等待B的位置插入wait操作,在B完成动作D之后插入signal操作。本题中存在两种同步关系:
(1)打印进程必须等待计算进程将计算结果放入缓冲之后,才能取结果打印,因此,可为它们设置初值为0的信号量Sa;
(2)除第一个计算结果可直接放入缓冲区外,计算进程必须等打印进程将缓冲中的前一个结果取走,缓冲区变空后,才能将下一个计算结果放入缓冲区,因此,可为它们设置初值为0的信号量Sb。
答2:计算进程和打印进程的算法可描述为:
semaphore Sa=0,Sb=0;
int buffer;
cp(){
int nextc;
compute the first number in nextc;
buffer = nextc;
signal(Sa);
while(1){
compute the next number in nextc;
wait(Sb);
buffer=nextc;
signal(Sa);
}
}
pp(){
int nextp;
while(1){
wait(Sa);
nextp=buffer;
signal(Sb);
print the number in nextp;
}
}
2.4 经典进程同步问题中的典型问题分析
2.4.1 在生产者--消费者问题中,如果将两个wait操作,即wait(full)和wait(mutex)互换位置,或者wait(empty)和wait(mutex)互换位置,其后果如何?如果将两个signal操作互换位置,即signal(full)和signal(mutex)互换位置,或者signal(empty)和signal(mutex)互换位置,其后果又如何?
答:在生产者--消费者问题中,如果将两个wait操作,即wait(full)和wait(mutex)互换位置,或者wait(empty)和wait(mutex)互换位置,都可能引起死锁。考虑系统中缓冲区全满时,若一生产者进程先执行了wait(mutex)操作并获得成功,当再执行wait(empty)操作时,它将因失败而进入阻塞状态,它期待消费者执行signal(empty)来唤醒自己,在此之前,它不可能执行signal(mutex)操作,从而使企图通过wait(mutex)进入自己的临界区的其他生产者和所有的消费者进程全部进入阻塞状态,从而引起系统死锁。类似的,消费者进程若先执行wait(mutex),后执行wait(full)同样可能造成死锁。
signal(full)和signal(mutex)互换位置,或者signal(empty)和signal(mutex)互换位置,则不会引起死锁,其影响只是改变临界资源的释放次序。
2.4.2 有三个进程PA、PB和PC协作解决文件打印问题。PA将文件记录从磁盘读入内存的缓冲区1,每执行一次读一个记录;PB将缓冲区1的内容复制到缓冲区2中,每执行一次复制一个记录;PC将缓冲区2的内容打印出来,每执行一次打印一个记录。缓冲区的大小与记录大小一样。请用信号量来保证文件的正确打印。
分析:本题又是生产者---消费者问题的一个变形,对缓冲区1来说,PA是生产者,PB是消费者;对缓冲区2来说,PB是生产者,PC是消费者。需要说明的有两点:
(1)缓冲区1和缓冲区2都只能存放一个记录,故无须设置in、out指针,原来生产者---消费者问题中的mutex信号量也因此可以省去;
(2)PB进程既是消费者,又是生产者。
答:该文件打印过程的同步算法可描述为:
semaphore empty1=1,full1=0,empty2=1,full2=0;
PA(){
while(1){
从磁盘读一个记录;
wait(empty1);
将记录存放到缓冲区1中;
signal(full1);
}
}
PB(){
while(1){
wait(full1);
从缓冲区1中取出一个记录;
signal(empty1);
wait(empty2);
将记录复制到缓冲区2中;
signal(full2);
}
}
PC(){
while(1){
wait(full2);
从缓冲区2中取出一个记录;
signal(empty2);
将取出的记录打印出来;
}
}
main(){
cobegin
PA();
PB();
PC();
coend
}
2.4.3 进程A1、A2、......、An1通过m个缓冲区向进程B1、B2、......、Bn2不断地发送消息。发送和接收工作遵循如下规则:
(1)每个发送进程一次发送一个消息,写入一个缓冲区,缓冲区大小和消息长度相同;
(2)对每一个消息,B1、B2、.......、Bn2都需要各接收一次,读入自己的数据区内;
(3)m个缓冲区都满时,发送进程等待;没有可读的消息时,接收进程等待。
试用wait、signal操作描述它们的同步关系。
分析:本题仍然是生产者---消费者问题的一个变形。由于每个缓冲区都只写一次,但要读n2次,故我们可将每个缓冲区看成是由n2格组成的。只有当某个缓冲区的n2格都空闲时,才允许写入,而且写一次缓冲相当于将该缓冲的n2格全部写一遍。Bj进程从缓冲中取消息时,它只取相应缓冲的第j格。由于每个Bj取消息的速度不同,故需要为它们分别设置指针outj,用来指示从哪个缓冲区的第j格中取消息。
答:我们将每个缓冲区看成是由n2格组成的,可为本题设置下列信号量:mutex,初值为1,用来实现对缓冲区的互斥访问;empty[i](i=1,......,n2),初值均为m,每个empty[i]对应于缓冲池的第i格中的所有空闲缓冲区;full[i](i=1,......,n2),初值均为0,对应缓冲池第i格中装有消息的缓冲区。另外还需要提供整型变量in,用来指示消息放入哪个缓冲区,out[j](j=1,.....,n2)用来指示Bj从哪个缓冲区中取消息,这些变量的初值均为0。Ai,Bj的算法描述如下:
Ai(){ //i=1,.....,n1
int k;
while(1){
for(k=1;k<=n2;k++) wait(empty[k]);
wait(mutex);
将Ai的消息放入第in个缓冲区中;
in=(in+1)%m;
signal(mutex);
for(k=1;k<=n2;k++) signal(full[k]);
}
}
Bj(){
while(1){
wait(full[j]);
wait(mutex);
从第out[j]个缓冲区的第j格中取出消息;
Out[j]=(out[j]+1)%m;
signal(mutex);
signal(empty[j]);
将消息写到数据区中;
}
}
2.4.4 桌上有个能盛得下五个水果的空盘子。爸爸不停地向盘中放苹果或桔子,儿子不停地从盘中取出桔子享用,女儿不停地从盘中取出苹果享用。规定三人不能同时从盘子中存放水果。试用信号量实现爸爸、儿子和女儿这三个循环进程之间的同步。
分析:本题是生产者---消费者问题的变形,相当于一个能生产两种产品的生产者(爸爸)向两个消费者(儿子和女儿)提供产品的同步问题,因此,需设置两个不同的full信号量apple和orange,初值均为0。
答:为了描述上述同步问题,可定义如下的信号量:
semaphore empty=5,orange=0,apple=0;mutex=1;
爸爸、儿子和女儿的算法可描述为:
Dad(){
while(1){
wait(empty);
wait(mutex);
将水果放入盘中;
signal(mutex);
if(放入的是桔子) signal(orange);
else signal(apple);
}
}
Son(){
while(1){
wait(orange);
wait(mutex);
从盘中取一个桔子;
signal(mutex);
signal(empty);
享用桔子;
}
}
Daughter(){
while(1){
wait(apple);
wait(mutex);
从盘中取一个苹果;
signal(mutex);
signal(empty);
享用苹果;
}
}
2.4.5 设有两个生产者进程A、B和一个销售者进程C,他们共享一个无限大的仓库,生产者每次循环生产一个产品,然后入库供销售者销售;销售者每次循环从仓库中取出一个产品进行销售。如果不允许同时入库,也不允许边入库边出库;而且要求生产A产品和B产品的件数满足以下关系:-n<=A的件数-B的件数<=m,其中n、m是正整数,但对仓库中A产品和B产品的件数无上述要求。请用信号量机制写出A、B、C三个进程的工作流程。
分析:本题中存在着以下的同步和互斥关系:
(1)生产者A、B和消费者C之间,不能同时将产品入库和出库,故仓库是一个临界资源。
(2)两个生产者之间必须进行同步,当生产的A、B产品的件数之差大于等于m时,生产者A必须等待;小于等于-n时,生产者B必须等待。可想象成有两种令牌,分别跟允许A和B生产的产品数量相关,A和B必须取得对应的令牌后才能生产产品,故这两类令牌也就是两种临界资源。
(3)生产者和销售者之间也必须进行同步,只有当生产者生产出产品并入库后,销售者才能进行销售。
答:为了互斥地入库和出库,需为仓库设置一初值为1的互斥信号量mutex;为了使生产的产品件数满足:-n<=A的件数-B的件数<=m,需设置两个信号量,其中SAB表示当前允许A生产的产品数量,其初值为m,SBA表示当前允许B生产的产品数量,其初值为n;还需设置一个初值为0的资源信号量S,对应于仓库中的产品量。具体的同步算法如下:
semaphore SAB=m,SBA=n,S=0,mutex=1;
PA(){
while(1){
wait(SAB);
produce a product A;
signal(SBA);
wait(mutex);
add the product A to the storehouse;
signal(mutex);
signal(S);
}
}
PB(){
while(1){
wait(SBA);
produce a product B;
signal(SAB);
wait(mutex);
add the product B to the storehouse;
signal(mutex);
signal(S);
}
}
PC(){
while(1){
wait(S);
wait(mutex);
take a product A or B from storehouse;
signal(mutex);
sell the product;
}
}
main(){
cobegin
PA();
PB();
PC();
coend
}
2.4.6 试用记录型信号量写出一个不会死锁的哲学家进餐问题的算法。
分析:此题有多种解决办法,其中之一是只允许4个哲学家同时进餐,以保证至少有一个哲学家可以进餐,最终才可能由他释放出其所用过的两只筷子,从而使更多的哲学家可以进餐。为此,需设置一个信号量Sm来限制同时进餐的哲学家数目,使它不超过4,故Sm的初值也应置成4(也可想象成桌上有4块令牌,只有拿到令牌的哲学家才能进餐,那样,令牌就是一种临界资源,故可为它们设置一个初值为4的信号量Sm)。
答:除了为每只筷子设置一个初值为1的信号量chopstick[i](i=0,......,4)外,还需再设置一个初值为4的信号量Sm,以限制同时就餐的哲学家人数不超过4.第i个哲学家的活动可描述为:
Pi(){
while(1){
wait(Sm);
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
eat;
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
signal(Sm);
think;
}
}
2.4.7 嗜睡的理发师问题:一个理发店由一个有N张沙发的等候室和一个放有一张理发椅的理发室组成。没有顾客要理发时,理发师便去睡觉。当一个顾客走进理发店时,如果所有的沙发都已被占用,他便离开理发店;否则,如果理发师正在为其他顾客理发,则该顾客就找一张空沙发坐下等待;如果理发师因无顾客正在睡觉,则由新到的顾客唤醒理发师为其理发。在理发完成后,顾客必须付费,直到理发师收费后才能离开理发店。试用信号量实现这一同步问题。
分析:本题中,顾客进程和理发师进程之间存在着多种同步关系:
(1)只有在理发椅空闲时,顾客才能坐到理发椅上等待理发师理发,否则顾客便必须等待;只有当理发椅上有顾客时,理发师才可以开始理发,否则他也必须等待。这种同步关系类似于单缓冲(对应于理发椅)的生产者---消费者问题中的同步关系,故可通过信号量empty和full来控制。
(2)顾客理完发后必须向理发师付费,并等理发师收费后顾客才能离开;而理发师则需等待顾客付费,并在收费后通知顾客离开,这可分别通过两个信号量payment和receipt来控制。
(3)为了控制顾客的人数,使顾客能在所有的沙发都被占用时离开理发店,还必须设置一个整型变量count来对占用沙发的顾客进行计数,该变量将被多个顾客进程互斥地访问并修改,故必须为它设置一个互斥信号量mutex。
(4)由于沙发全被占用时,顾客自动离开,也就是说,所有进店的顾客必能得到一张沙发,故不再为沙发设置互斥信号量。
答:为解决上述问题,需设置一个整型变量count用来对占用沙发的顾客进行计数,并需设置5个信号量,其中,mutex用来实现顾客进程对count变量的互斥访问,其初值为1;empty表示是否有空闲的理发椅,其初值为1;full表示理发椅上是否坐有等待理发的顾客,其初值为0;payment用来等待付费,其初值为0;receipt用来等待收费,其初值为0。具体的算法描述如下:
int count=0;
semaphore mutex=1,empty=1,full=0;
semaphore payment=0,receipt=0;
guest(){
wait(mutex);
if(count>=N){ //沙发已被全部占用
signal(mutex);
离开理发店;
}else{
count++;
signal(mutex);
在沙发中就座;
wait(empty); //等待理发椅变空
离开沙发,坐到理发椅上;
wait(mutex);
count--;
signal(mutex);
signal(full); //唤醒理发师
理发;
付费;
signal(payment); //通知理发师付费
wait(receipt); //等理发师收费
signal(empty); //离开理发椅
离开理发店;
}
}
Baber(){
while(1){
wait(full); //如没顾客就在此睡觉
替顾客理发;
wait(payment); //等顾客付费
收费;
signal(receipt); //通知顾客收费完成
}
}
2.4.8 请给出一个写者优先的“读者--写者”问题的算法描述。
分析:与读者优先不同的方案有三种。
第一种是读者和写者的地位是完全平等的,即无论是读者还是写者,都按他们到达的时间先后决定优先次序。。
第二种方案中,写者的优先权得到了提高,先于写者到达的读者比写者优先,但当一个写进程声明要进行写操作时,其后续读者必须等写操作完成之后,才能进行读;而且,如果在写完成之前,又有新的写者到达,那新的写者的优先权将高于已在等待的读者。
第三种方案写者的优先权更高,某个写者到达时,即使他是目前唯一的写者,那些先于他到达但还没来得及读的读者都将等待他完成写操作。
答:为了使写者优先,可在原来的读优先算法的基础上增加一个初值为1的信号量S,使得当至少有一个写者准备访问共享对象时,他可使后续的读者进程等待写完成;初值为0的整型变量wirtecount,用来对写者进行计数;初值为1的互斥信号量wmutex,用来实现多个写者对writecount的互斥访问。读者动作的算法描述如下:
reader(){
while(1){
wait(S);
wait(rmutex); //rmutex用来实现对readcount的互斥访问
if(readcount==0) wait(mutex); //mutex用来实现对读写对象互斥访问
readcount++;
signal(rmutex);
signal(S);
perform read operation;
wait(rmutex);
readcount--;
if(readcount==0) signal(mutex);
signal(rmutex);
}
}
写者动作的算法描述如下:
writer(){
while(1){
wait(wmutex); //wmutex用来实现对writecount的互斥访问
if(writecount==0) wait(S);
writecount++;
signal(wmutex);
wait(mutex);
perform write opertion;
signal(mutex);
wait(wmutex);
writecount--;
if(writecount==0) signal(S);
signal(wmutex);
}
}
上述算法是按第二种方案写的,对于第一种方案,只需去掉算法中跟writecount变量相关的部分,让所有的写者(而不仅仅是第一个写者),在到达时都执行wait(S)就可以了。第三种方案,可对读者进程再增加一个初值为1的信号量RS,并在wait(S)前先执行wait(RS)操作,signal(S)后再执行signal(RS),则可以使读者不会在S上排成长队,从而使写者的优先权得到进一步提升。
2.4.9 请用信号量解决以下的“过独木桥”问题:同一方向的行人可连续过桥,当某一方向有人过桥时,另一方向的行人必须等待;当某一方向无人过桥时,另一方向的行人可以过桥。
分析:独木桥问题是读者---写者问题的一个变形,同一个方向的行人可以同时过桥,这相当于读者可以同时读。因此,可将两个方向的行人看做是两类不同 的读者,同类读者(行人)可以同时读(过桥),但不同类读者(行人)之间必须互斥地读(过桥)。
答:可为独木桥问题定义如下变量:
int countA=0,countB=0; //countA、countB分别表示A、B两个方向过桥的行人数量
semaphore bridge=1; //用来实现不同方向行人对桥的互斥共享
semaphore mutexA=mutexB=1; //分别用来实现对countA、countB的互斥共享A方向的所有行人对应相同的算法,他们的动作的算法可描述为:
PA(){
wait(mutexA);
if(countA==0) wait(bridge);
countA++;
signal(mutexA);
过桥;
wait(mutexA);
countA--;
if(countA==0) signal(bridge);
signal(mutexA);
}
B方向行人的算法与上述算法类似,只需将其中的mutexA、countA换成mutexB和countB即可。
2.4.10 有一间酒吧里有3个音乐爱好者队列,第1队的音乐爱好者只有随身听,第2队的音乐爱好者只有音乐磁带,第3队的音乐爱好者只有电池。而要听音乐就必须随身听、音乐磁带和电池这三种物品俱全。酒吧老板一次出售这三种物品种的任意两种。当一名音乐爱好者得到这三种物品并听完一首乐曲后,酒吧老板才能再一次出售这三种物品种的任意两种,于是第2名音乐爱好者得到这三种物品,并开始听乐曲。全部买卖就这样进行下去。试用信号量实现他们的同步关系。
分析:
(1)根据题意,当酒吧老板提供两种物品时,必须被同一个音乐爱好者取走,我们应把每两种物品看成是一个组合起来的临界资源。第1队的音乐爱好者等待的组合资源是音乐磁带和电池,为它设置一个信号量S1;第2队音乐爱好者等待的组合资源是随身听和电池,为它设置一个信号量S2;第3队的音乐爱好者等待的组合资源是随身听和音乐磁带,为它设置一个信号量S3。S1、S2、S3的初值均为0;
(2)只有当一个音乐爱好者听完一首乐曲后,酒吧老板才能再次出售商品,为这种同步关系也必须设置一个初值为0的信号量music_over。
答:他们的同步关系可用算法描述如下:
semaphore S1=S2=S3=0;
semaphore music_over=0;
fan1(){
wait(S1);
买音乐磁带和电池;
听音乐;
signal(music_over);
}
fan2(){
wait(S2);
买随身听和电池;
听乐曲;
signal(music_over);
}
fan3(){
wait(S3);
买到随身听和音乐磁带;
听乐曲;
signal(music_over);
}
boss(){
while(1){
提供任意两种物品出售;
if(提供的是音乐磁带和电池) signal(S1);
else if(提供的是随身听和电池) signal(S2);
else signal(S3);
wait(music_over);
}
}
main(){
cobegin
fan1();
fan2();
fan3();
boss();
coend
}
2.5 消息传递通信机制中的典型问题分析
2.5.1 消息缓冲队列通信机制应具有哪几方面的功能?
答:在消息缓冲队列通信机制中,应具有如下几方面的功能。
(1)构成消息。发送进程在自己的工作区设置发送区a,将消息正文和有关控制信息填入其中。
(2)发送消息。将消息从发送区a复制到消息缓冲区,并把它插入到目标进程的消息队列中。
(3)接收消息。由目标进程从自己的消息队列中找到第一个消息缓冲区,并将其中的消息内容拷贝到本进程的接收区b中。
(4)互斥与同步。互斥是保证在一段时间内只有一个进程对消息队列进行操作;同步是指在接收进程和发送进程之间进行协调,为此,应在接收进程的PCB中,设置用于实现互斥和同步的信号量。
2.5.2 试比较直接通信方式和间接通信方式。
答:可以从以下几个方面来比较直接通信方式和间接通信方式。
(1)发送和接收原语。直接通信原语通常为send(receiver,message)、receive(sender,message);间接通信原语通常为send(mailbox,message)、receive(mailbox,message),而且它还需要提供有关信箱创建和撤销的原语。
(2)提供对方的标识符。直接通信要求发送双方显式地提供对方的标识符,对接收进程,如果允许它同时接收多个进程发来的消息,则接收原语中的发送进程标识符可以是通信完成后返回的值;间接通信则不要求它们显式地提供对方的标识符,而只需提供信箱标识。
(3)通信链路。直接通信时,进程只需提供对方的标识符便可进行通信,在收发双方之间建立通信链路由系统自动完成,并且在收发双方之间有且仅有一条通信链路;间接通信时,仅当一对进程共享某个信箱时,它们之间才有通信链路,每对进程间可以有多条链路。
(4)实时性。直接通信通常只能提供实时的通信;而间接通信则既可实现实时通信,也可实现非实时通信。
2.6 线程中的典型问题分析
2.6.1 试从调度性、并发性、拥有资源、独立性、系统开销以及对多处理机的支持等方面,对进程和线程进行比较。
答:进程和线程之间在调度性、并发性、拥有资源、独立性、系统开销及对多处理机的支持方面的比较如下。
(1)调度性。在传统的操作系统中,拥有资源的基本单位、独立调度和分派的基本单位都是进程。而在引入线程的OS中,则把线程作为调度和分派的基本单位,进程只是拥有资源的基本单位,而不再是调度和分派的基本单位。
(2)并发性。在引入线程的OS中,不仅进程间可以并发执行,而且在一个进程内的多个线程间,也可以并发执行,因而比传统的OS具有更好的并发性。
(3)拥有资源。在这两种OS中,拥有资源的基本单位都是进程。线程除了一点在运行中必不可少的资源(如线程控制块、程序计数器、一组寄存器值和堆栈)外,本身基本不拥有系统资源,但它可共享其隶属进程的资源。
(4)独立性。每个进程都能独立地申请资源和独立地运行;但同一进程的多个线程则共享进程的内存地址空间和其他资源,它们之间的独立性比进程之间的独立性要低。、
(5)开销。由于创建或撤销进程时,系统都要为之分配和回收资源,如内存空间等。进程切换时所要保存和设置的现场信息也要明显地多于线程,因此,OS在创建、撤销和切换进程时所付出的开销显著地大于线程。另外,由于隶属于同一个进程的多个线程共享同一地址空间和打开文件,从而使它们之间的同步和通信的实现也变得更为容易。
(6)支持多处理机系统。传统的进程,只能运行在一个处理机上;多线程的进程,则可以将进程中的多个线程分配到多个处理机上,从而获得更好的并发执行效果。
2.6.2 什么是内核支持线程和用户级线程?并对它们进行比较。
答:内核支持线程是在内核支持下实现的,即每个线程的线程控制块设置在内核中,所有对线程的操作(如创建、撤销和切换等),都是通过系统功能调用由内核中的相应处理程序完成。而用户级线程仅存在于用户空间中,即每个线程的控制块设置在用户空间中,所有对线程的操作也在用户空间中完成,而无需内核的帮助。
可从以下几个方面比较内核支持线程和用户级线程。
(1)内核支持。用户级线程可在一个不支持线程的OS中实现,而内核支持线程则不然,它需要得到OS内核的支持。
(2)处理器的分配。在多处理机环境下,对纯粹的用户级线程来说,内核一次只为一个进程分配一个处理器,即进程无法享用多处理机带来的好处;而在设置有内核支持线程时,内核可调度一个应用中的多个线程同时在多个处理器上并行运行,从而提高程序的执行速度和效率。
(3)调度和线程执行时间。对设置有内核支持线程的系统,内核的调度方式和算法与进程的调度十分相似,只不过调度的单位是线程;而对只设置了用户级线程的系统,内核调度的单位则仍为进程,当一进程得到CPU时,隶属于该进程的多个线程可通过用户态的线程调度分享内核分配给进程的CPU时间。因此,在条件相同的情况下,内核支持的线程通常比用户级线程得到更多的CPU执行时间。
(4)切换速度。用户级线程的切换,通常发生在一个应用程序的诸线程之间,由于不需陷入内核,而且切换的规则也相当简单,因此切换速度比内核支持线程至少快一个数量级。
(5)系统调用。在典型的OS中,许多系统调用都会引起阻塞。当一个用户级线程执行这些系统调用时,被阻塞的将是整个进程;而当一个内核支持线程执行这些系统调用时,内核只阻塞这个线程,但仍可调度其所属进程的其他线程执行。
逆风而行,扬帆远航~