习 题
0 进程和线程的本质区别是什么?
答:进程是一组相关资源的集合。进程有一个存放程序正文和数据以及其他资源的地址空间。这些资源包括打开的文件、子进程、未处理的定时器、信号处理器和审计信息。通过进程形式把他们放在一起,方便进行管理。
线程是进程的一个执行流。线程有一个程序计数器,用来跟踪下一条将要执行的指令。它有寄存器,存储当前使用的变量。它有堆栈,存储着执行的历史,其中每一栈帧保存了没有返回的过程调用。
尽管线程必须在进程中执行,但线程和它的进程是可以分别对待处理的两个不同概念。进程用来集合资源,而线程是CPU中的调度的实体。
1 假设你正在设计一种先进的计算机体系结构,它使用硬件而不是中断来完成进程切换,则CPU需要哪些信息?请描述用硬件完成进程切换的工作过程
答:应该有一个寄存器包含当前进程表项的指针。当I/O结束时,CPU将把当前的机器状态存入到当前进程表项中。然后,将转到中断设备的中断向量,读取另一个过程表项的指针(服务例程),然后,就可以启动这个进程了。
2 目前的计算机上,中断处理程序至少有一小部分用汇编语言编写,为什么?
答:通常,高级语言不允许访问CPU硬件,而这种访问是必需的。例如,中断处理程序可能需要禁用和启用某个特定设备的中断服务,或者处理进程堆栈区的数据。另外,中断服务例程需要尽快地执行。
3 书中认为图2-6(a)的模型不适用于在内存进行高速缓存的文件服务器,为什么?可否使每个进程拥有自己的cache?
答:(进程相互独立,当两进程同时操作内存,一个写一个读,可能造成不一致。)即使是有可能实现,也是很难保持文件系统的一致性。假设某个客户进程给服务器进程1发送请求要更新文件。该进程更新其内存的cache项。然后,另一个客户进程给服务器进程2发送请求读取该文件。不幸的是,如果该文件还在 cache中,服务器进程2对此毫不知情,将返回过时的数据。如果第一个进程在缓冲后将文件写到磁盘中, 而服务器进程2每次读取时检查磁盘其缓存的备份是否是最新的,系统还可以工作,但是需要避免磁盘访问的所有缓存系统。
4 在使用线程的系统中,是每个线程有一个堆栈还是每个进程有一个堆栈,说明原因。
答:每个线程都是自己调用例程,因此它必须有其自己的堆栈以保存局部变量、返回地址等等。这一点用户级线程和内核级线程是一样的。
5 什么是竞争条件?
答:两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,就称为竞争条件(race conditions)。
6 写一个shell程序,其功能是产生一个内容为一个整数序列的文件,要求它先读取文件中的最后一个整数,将其加1,然后将这个新整数追加到文件的末尾。在系统前台和后台同时运行它并使用相同的文件名。在因竞争而造成的故障发生之前它能运行多久?此处的临界区是什么?请对其进行修改以防止发生竞争。(提示:使用ln file file.lock来将数据文件加锁)
7 对于前一问题,如下的语句 ln file file.lock 是一种很有效的加锁机制吗?说明原因。
答:
一个可行的shell脚本应该如下:
if[ ! –f numbers ]; then echo0> numbers; fi
count=0
while(test $count !=200)
do
count=‘expr $count +1’
n=‘tail –1numbers’
expr $n +1>>numbers
done
同时运行该脚本两次,通过后台启动它一次(使用)和再次在前台启动。然后检查文件编号。它可能开始看起来会像数字的有序列表,但在某一时刻,由于运行脚本的两个副本而创建的竞争条件,它就失去了它的规律。通过对脚本的每一个副本测试,并在进入关键区域之前设置一个锁,在离开关键区域时打开它,可以避免竞争。可以这样做:
ifln numbers numbers.lock
then
n=‘tail –1numbers’
expr $n +1>>numbers
rm numbers.lock
fi
此版本只是当文件无法访问时直接跳过,不同的解决方案可以让进程休眠,忙等待,或仅仅循环计数,使得操作成功。
8 两个进程在一台共享内存的多处理机(即共享同一个存储器)上运行时,图2-8所示的采用变量turn的忙等待方案还奏效吗?
答:可能一个进程储存的内容在其挂起时被另一个进程修改。忙等待应该被避免,浪费CPU时间,轮流进入临界区如果一个进程比另一进程慢很多时,不适用。
9 现有一台计算机,不具备TEST AND SET LOCK指令,但有一条指令可以按原子操作方式将一个寄存器的值和一个存储器字进行交换,能否利用该指令写一个与图2-10中enter_region类似的例程?
第一条指令将lock原来的值拷贝到寄存器中并将lock置为1,随后这个原先的值与0相比较。如果它非零,则说明先前已被上锁,则程序将回到开头并再次测试。经过或长或短的一段时间后它将变成0(当前处于临界区中的进程退出临界区时),于是子例程返回,并上锁。清除这个锁很简单,程序只需将0存入lock即可,不需要特殊的指令。
进程在进入临界区之前先调用enter_region。这将导致忙等待,直到锁空闲为止。随后它获得锁变量并返回。在进程从临界区返回时它调用leave_region,这将把lock置为0。与临界区问题的所有解法一样,进程必须在正确的时间调用enter_region和leave_region,解法才能奏效。如果一个进程有欺诈行为,则互斥将会失败。
10 给出一个框架,来描述一个可禁止中断的操作系统如何实现信号量。
11 请说明如何只利用二进制信号量和普通的机器指令来实现计数信号量(即可以拥有任意大的数值的信号量)。
答:将每个计数信号量与2个二值信号量联合:M用于互斥;S用于阻塞。另外,每个计数信号量都组合一个用于保存up次数减去down次数的计数器,以及在该信号量上阻塞的进程列表。为了实现down操作,进程首先通过对M执行down操作,以获得对信号量、计数器以及列表的独占访问权。然后,将计数器减 1。如果大于等于0, 只需对M执行up操作并退出即可。如果M为负数,就将该进程放入阻塞进程列表中。接着,对M执行up操作,对S执行down操作来阻塞该进程。为了实现up操作,首先对M执行down操作以获得互斥,然后将计数器加1。如果计数器大于0, 则没有进程阻塞,就只需对M执行up操作。不过, 如果计数器小于等于0, 则必须从列表中移出某些进程。最后,按次序对B和M执行up操作。
12 在 2.2.4节中描述了一个高优先级进程H和低优先级进程L的情况,它最终导致H陷入死循环,若采用时间片调度而不是优先级调度,还能发生这种情况吗?请进行讨论。
考虑一台计算机有两个进程,H优先级较高,L优先级较低。调度规则规定只要H处于就绪态它就可以运行。在某一时刻,L处于临界区中,此时H变到就绪态准备运行(例如,一条I/O操作结束)。现在H开始忙等待,但由于当H就绪时L不会被调度,也就无法离开临界区,所以H将永远忙等待下去。这种情况有时被称作优先级翻转问题(priority inversion problem)。
时间片调度:每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。时间片轮转调度很容易实现。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。
答:不会。
13 管程内部的同步机制使用条件变量和两个特殊操作WAIT和SIGNAL,一种更一般的同步方式只有一条原语WAITUNTIL,它以任意的布尔表达式作为参数。例如 WAITUNTIL x<0 or y+z<n 这样便不再需要SIGNAL原语。很显然这个方案比 Hoare 和Brinch Hansen的方案更通用,但它从未被采用过,为什么?(提示:从实现考虑)
答:其实现的代价很高。 每次在某些等待变化的进程的谓词中出现的任何变量, runtime系统都必须重新计算该谓词,以判断该进程是否能够被解锁。而对于 Hoare和Brinch Hansen管程,则只需signal原语即可唤醒进程。
14 一个快餐厅有四种职员:(1)领班,他们接收顾客点的菜单(2)厨师,准备饭菜(3)打包工,将饭菜装在袋子里(4)出纳员,收钱并将食品袋交给顾客。每个职员可被看作一个进行通信的串行进程,它们采用的进程间通信方式是什么?将该模型与MINIX中的进程加以比较。
答:雇员之间通过消息传递进行通信:在该例中,消息为订单、食物和袋子。在UNIX中,该4个进程通过管道连接。
15 假设有一消息传递系统使用信箱,一个进程向满信箱发消息或从空信箱收消息都不会阻塞,进程对错误码的处理方式为重试,直到成功为止,这种方案会带来竞争吗?
答:它不会导致竞争条件(不会丢失任何东西),不过它是完全的忙等待。
16 在图2-20所示的哲学家用餐问题的解法中,为什么过程take_forks将状态变量置为HUNGRY?
使用一个数组state来跟踪一个哲学家是在吃饭、思考还是正在试图拿叉子。一个哲学家只有在两个邻居都不在进餐时才允许转移到进餐状态。第i位哲学家的邻居由宏LEFT和RIGHT定义,换言之,若i为2,则LEFT为1,RIGHT为3。哲学家在拿起叉子take_forks时,将其状态status[i]=HUNGER。
17 考虑图2-20中的过程put_forks,假设变量state[i]在对test的两次调用之后被置为THINKING,而不是在调用之前。对于3位哲学家的情况这个改动有什么影响?对于100位哲学家的情况呢?
答:可能发生阻塞的情况。该变化将意味着在哲学家停止进餐后,他的邻居都不能接着被选择。事实上,他们永远不会被选择。假设哲学家2完成了进餐,他将为哲学家1和3运行test,而两者都不会被启动,即使他们两个都饿了而且两个叉子都是可用的。类似的,如果哲学家4完成进餐,哲学家3也不会被启动。他将无法启动。
哲学家问题对于多个竞争进程互斥地访问有限资源(如I/O设备)这一类问题的建模十分有用。
18 从何种类型的进程可以在何时被启动的角度来看,读者-写者问题可以通过几种方式进行形式化。根据优先哪几类进程的不同,请详细地描述该问题的三种变体。对每种变体,请说明当一个读者或写者能够访问数据库时情况将会怎样,以及当一个进程对数据库访问结束后又将会怎样。
读者-写者问题,它为数据库访问建立了一个模型。例如,设想一个飞机定票系统,其中有许多竞争的进程试图读写其中的数据。多个进程同时读是可以接受的,但如果一个进程正在更新数据库,则所有其他进程都不能访问数据库,即使读操作也不行。
答:变种1:读者优先。当读者活跃时,写者都无法启动。当一个新的读者出现时,它可以立即开始除非当前有写者是活跃的。当写者完成时,如果有读者在等待,他们全都启动,无论是否有写者存在。
变种2:写者优先。当有写者等待时,读者都不会开始。当最后活跃的进程结束,如果有写者,就启动它;否则,所有读者(如果有)全部开始。
变种3:平衡的版本。当有读者是活跃的,新的读者可以立即开始。当写者完成时,新的写者优先,如果有写者等待的话。也就是说,一旦开始读,就一直读到没有读者为止。同样地,一旦开始作,所有挂起的写者都被允许运行。
19 CDC6600计算机使用一种有趣的称作处理器共享的时间片调度算法,它可以同时处理多达10个I/O进程,每条指令结束后都进行进程切换,这样进程1执行指令1,进程2执行指令2,等等。进程切换由特殊的硬件完成,所以没有开销。如果在没有竞争的条件下一个进程需要T秒钟完成,那么当有n个进程共享处理器时需要多长时间完成?
答:它需要nT sec。
20 时间片调度程序通常维护一个有所有就绪进程组成的队列,每个进程在队列中出现一次。如果一个进程在队列中出现两次以上,情况将会怎样?你能设想出这种情况出现的原因吗?
答:间片调度:每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。时间片轮转调度很容易实现。调度程序所要做的就是维护一张就绪进程列表,如图2-22(a)所示,当进程用完它的时间片后,它被移到队列的末尾,如图2-22(b)所示。
21 对某系统进行监测后表明平均每个进程在I/O阻塞之前的运行时间为T。一次进程切换需要的时间为S,这里S实际上即为开销。对于采用时间片长度为Q的时间片调度法,对以下各种情况给出CPU利用率的计算公式。
(a) Q=∞
(b) Q>T
(c) S<Q<T
(d) Q=S
(e) Q 趋近于0
答:CPU的效率就是有用的CPU时间除以整个的CPU时间。当Q > T时,基本的周期就是进程运行T,然后进程切换S。因此,(a)和(b)的效率都是T/(T+S)。当时间片比T短时,每运行一次T就要求T/Q次进程切换,浪费时间为ST/Q。因此,其效率为T/(T+ST/Q)也就是下降到 Q/(Q+S),这就是(c)的答案。至于(d),只需以S替代Q,就可以计算出其效率为50%。最后,(e)的效率趋近于0。
22 有5个待运行任务,各自预计运行时间分别是9, 6, 3, 5和X。采用哪种运行次序将使平均响应时间最短? (答案依赖于X)
答:最短作业优先可以使得平均响应时间最短。
0 < X ≤ 3: X, 3, 5, 6, 9.
3 < X ≤ 5: 3, X, 5, 6, 9.
5 < X ≤ 6: 3, 5, X, 6, 9.
6 < X ≤ 9: 3, 5, 6, X, 9.
X > 9: 3, 5,6, 9, X.
23 有5个批处理任务A到E几乎同时到达一计算中心。其预计运行时间分别为10, 6, 2, 4和8分钟。其优先级(由外部设定)分别为3,5,2,1和4,这里5为最高优先级。对于下列每种调度算法,计算其平均进程周转时间,进程切换开销可忽略。
(a) 时间片轮转
(b) 优先级调度
(c) 先来先服务(按照次序 10, 6, 2, 4, 8)
(d) 最短作业优先
对(a),假设系统具有多道处理能力,每个作业均获得公平的CPU份额,对(b)到(d)假设一时刻只有一个作业运行,直到结束。所有的作业都是完全的CPU密集型作业。
答:对于时间片轮转,在头10分钟里,每个作业获得1/5的CPU时间。在第10 分钟时,C结束。在接下来的8分钟里,每个作业获得 1/4 的CPU时间,然后D完成,然后,在接下来的6分钟内,余下的3个作业各获得1/3的CPU时间,直到B结束,以此类推。因此,5个作业的完成时间分别为是10, 18, 24, 28和30, 平均为22分钟。
对于优先级调度,5最先运行,6分钟完成。其它作业分别在第14, 24, 26和30分钟完成,平均为18.8分钟。
如果作业按A->E的次序执行,则分别在第10,16, 18, 22和30分钟完成,因此,平均为19.2分钟。
最后,最短作业优先调度的完成时间分别为第2, 6, 12, 20和30分钟,平均为14分钟。
24 在CTSS上运行的一个进程需要30个时间片方能结束,则它需要被换入多少次?包括第1次,即开始运行之前。
CTSS(多重队列)是最早使用优先级调度的系统之一。但是CTSS存在进程切换速度太慢的问题,其原因是IBM 7094内存中只放得下一个进程,每次切换都需要将当前进程换出到磁盘,并从磁盘上读入一个新进程。CTSS的设计者很快便认识到为CPU密集的进程设置较长的时间片,比频繁地分给它们很短的时间片要高效(减少交换次数)。另一方面,如前所述,给进程长时间片又会影响响应时间。他们的解决办法是设立优先级类。属于最高级类的进程运行一个时间片,属于次高优先级类的进程运行2个时间片,再次一级运行4个时间片,依次类推。当一个进程用完分配的时间片后,它被移到下一类。
答:第一次得到 1 个时间片。随后获得 2, 4, 8 和 15 个时间片,因此必须经过 5 次交换。
25 使用一个参数 a=1/2的老化算法来预测运行时间。从最早到最近的前4次执行时间分别为40,20,40和15毫秒,则下次运行时间预计为多长?
答:预测值的顺序为40,30,35,所以下一次是25。(把前两个数据加一起,除以2,然后把结果和下一个数据加一起,除以2。)
26 一个软实时系统有4个周期性事件,其周期分别为50,100,300和250毫秒。假设其处理分别需要35, 20,10和X毫秒,则该系统可调度所允许的X值最大是多少?
答:所使用的 CPU 的片断为 35/50 + 20/100 + 10/200 + x/250。为了使得进程可调度,必须是总和小于1。因此,x必须小于等于2.5ms。
27 解释两级调度为什么被广泛采用?
答:当内存太小不能载入所有就绪进程时,就需要使用两级调度。某些进程被载入内存,并且从中选择一个运行。内存中进程会随着时间调整。这种算法容易实现也非常有效,另外,时间片轮转调度并不管进程是否在内存中。
28 MINIX在执行期间维护一个变量proc_ptr,它指向当前进程的进程表项,为什么?
29 MINIX对消息不加缓冲,请解释这样的设计会对时钟和键盘中断带来什么问题?
30 在MINIX中当一条消息被发送给一个睡眠进程时,将调用过程ready来将该进程挂入适当的调度队列中,该过程首先要关中断,为什么?
31 MINIX中的mini_rec过程包含一个循环,请解释为什么需要该循环。
32 MINIX使用图2-23所示的调度方法,其中不同类型的进程有不同的优先级。优先级最低的进程(用户进程)使用时间片调度法,而系统任务和服务器进程则允许一直运行到阻塞。请问优先级最低的进程是否会发生饥饿,为什么?
33 MINIX适用于实时应用吗?例如数据日志记录。若不适用,可对其作什么改动?
34 设你有一个提供信号量的操作系统,请实现一条消息传递系统,写出发送和接收消息的过程。
35 一个主修人类学、辅修计算机科学的学生参加了一个课题,调查非洲狒狒是否能被教会理解死锁。他找到一处很深的峡谷,在上边固定了一根横跨峡谷的绳索,这样狒狒就可以攀住绳索越过峡谷。同一时刻可以有几只狒狒通过,只要它们朝着相同的方向。但如果向东和向西的狒狒同时攀在绳索上则将发生死锁(狒狒将被卡在中间),因为它们无法在吊在峡谷上时从另一只的背上翻过去。如果一只狒狒想越过峡谷,它必须看当前是否有别的狒狒正在逆向通过。使用信号量写一个避免死锁的程序来解决该问题。
36 继续前一问题,但现在要避免饥饿。当一只想向东去的狒狒到了绳索跟前,但发现有别的狒狒正在向西越过峡谷时,它将一直等到绳索可用为止。但在至少有一只狒狒向东越过峡谷之前,不允许再有狒狒开始从东向西越过峡谷。
37 使用管程,而不是信号量来解决哲学家用餐问题。
38 在MINIX核心中增加一些代码来跟踪从进程(任务)i发送到进程(任务)j的消息个数,按下F4键时打印出该矩阵。
39 修改MINIX的调度程序以跟踪每个用户进程最近使用的CPU时间。当没有任务或服务器进程运行时,要求选择使用CPU最少的用户进程运行。
40 重新设计MINIX,使得每个进程的进程表中有一个优先级域可用来对单个进程设置更高或更低的优先级。
41 修改mpx386.s中的宏hwint_master 和hwint_slave,使得当前由save函数执行的操作改为由在线代码执行。这样作使代码增大了多少?你能测出性能提高了多少吗?