如有错误答案,请各位评论指出,多谢多谢~~
1、图2-2中给出了三个进程状态,在理论上,三个状态可以有六种转换,每个状态两个。但是,图中只给出了四种转换。有没有可能发生其他两种转换中的一个或两个?
从阻塞到运行的转换是可以想象的。假设某个进程在I/O上阻塞,而且I/O结束,如果此时CPU空闲,该进程就可以从阻塞态直接转到运行态。而另外一种转换(从就绪态到阻塞)是不可能的。一个就绪进程是不可能不做任何事情就直接阻塞,必定要经过运行这一个状态。
2.假设要设计一种先进的计算机体系结构,它使用硬件而不是中断来完成进程切换。CPU需要哪些信息?请描述用硬件完成进程切换的工作过程。
应该有一个寄存器包含当前进程表项的指针。当I/O结束时,CPU将把当前的机器状态存入到当前进程表项中。然后,将转到中断设备的中断向量,读取另一个进程表项的指针(服务例程),然后,就可以启动这个进程了。
3、在所有当代计算机中,至少有部分中断处理程序是用汇编语言编写的。为什么?
通常,高级语言不允许访问CPU硬件,而这种访问是必需的。例如,中断处理程序可能需要禁用和启用某个特定设备的中断服务,或者处理进程堆栈区的数据。另外,中断服务例程需要尽快地执行。
4、当中断或系统调用把控制转给操作系统时,通常将内核堆栈和被中断进程的运行堆栈分离。为什么?
内核使用单独的堆栈有若干的原因。其中两个原因如下:
- 首先,不希望操作系统崩溃,由于某些用户程序不允许足够的堆栈空间。
- 第二,如果内核将数据保留在用户空间,然后从系统调用返回,那么恶意的用户可能使用这些数据找出某些关于其它进程的信息。
5、一个计算机系统的内存有足够的空间容纳5个程序。这些程序又一半时间处于等待I/O的空闲状态。请问CPU时间浪费的比例是多少?
五个进程都空闲的概率是1/32,所以CPU空闲时间是1/32。
6、一个计算机的RAM有4GB,其中操作系统占512M。所有进程都占256M并且特征相同。要是CPU利用率达到99%, 最大I/O等待是多少?
内存中有足够的空间容纳14个进程。如果一个进程的I/O是P,那么它们都在等待I/O的概率是P 14。通过将其等于0.01,我们得到方程p 14=0。01。解决这个问题,我们得到p=0。72,因此我们可以容忍高达72%I/O等待的进程
7、多个作业能够并行运行,比它们顺序执行完成的要快。假设有两个作业同时开始执行,每个需要10分钟的CPU时间。如果顺序执行,那么最后一个作业需要多长时间可以完成?如果并行执行又需要多长时间?假设I/O等待占50%。
CPU利用率计算公式:CPU利用率 = 1 - p^n 。设运行作业所需要的时间为T。
如果每个工作都有50%的I/O等待,那么在没有竞争的情况下,完成该工作需要40分钟。如果按顺序运行,第二个将在第一个启动后80分钟完成。对于两个作业,CPU利用率大约为1-0.5^2。因此,每一个系统每分钟可获得0.375 cpu分钟的实时数据。要累积20分钟的CPU时间,作业必须运行20/0.375分钟,或大约53.33分钟。因此,按顺序运行的作业在80分钟后完成,但并行运行的作业在53.33分钟后完成。
8、考虑一个6级多道程序系统(内存可同时容纳6个程序)。假设每个进程I/O等待时间40%,那么CPU利用率是多少?
所有进程等待I/O的概率为0.4^6,即0.004096。因此,CPU利用率=1−0。004096=0:995904。
9、假设要从互联网去哪个上下载一个2GB大小文件,文件内容可以从一组镜像服务器获得,每个服务器可以传输文件的一部分,假定每个传输请求给定开始字节可结束字节,如何用多线程优化下载?
客户机进程可以创建单独的线程;每个线程可以从一个镜像服务器获取文件的不同部分。这有助于减少停机时间。当然,所有线程都共享一个网络链接。当线程数量变得非常大时,此链接可能成为瓶颈。
10、为什么图2-11a的模式不适合用于使用内存高速缓存的文件服务器。为什么不适合?每个进程可以有自己的高速缓存吗?
即使是有可能实现,也是很难保持文件系统的一致性。假设某个客户进程给服务器进程1发送请求要更新文件。该进程更新其内存的cache项。然后,另一个客户进程给服务器进程2发送请求读取该文件。不幸的是,如果该文件还在 cache中,服务器进程2对此毫不知情,将返回过时的数据。如果第一个进程在缓冲后将文件写到磁盘中, 而服务器进程2每次读取时检查磁盘其缓存的备份是否是最新的,系统还可以工作,但是需要避免磁盘访问的所有缓存系统。
11、当一个多线程进程创建子进程时,若子进程得到全部父进程线程的副本,会出现问题。假如原有线程之一正在等待键盘输入,现在则成为两个线程在等待键盘输入,每个进程有一个。在单线程进程中也会发生这种问题吗?
不会。如果单线程进程在键盘上阻塞,就不能创建子进程。
12、在图2-8中,给出了一个多线程Web服务器。如果读取文件的惟一途径是正常的阻塞read系统调用,那么Web服务器应该使用用户级线程还是内核级线程?为什么?
当工作者线程从磁盘读取Web页时,它就会被阻塞。如果使用用户级线程,该动作将阻塞整个进程,而破坏多线程的价值。这就是使用内核线程的原因:某些线程的阻塞不会影响到其他线程。
13、在本章中,我们介绍了多线程Web服务器,说明它比单线程服务器和有限状态机服务器更好的原因。存在单线程服务器更好一些的情形吗?请给出一个例子。
是的。如果服务器是完全CPU绑定的,则不需要多线程。这只会增加不必要的复杂性。假设某个百万人口区域的电话查号系统(类似于114),如果每个(姓名,电话号码)记录为64个字符,整个的数据库则为64MB,这就很容易全部读入服务器内存中以提供快速的查询。
14、既然计算机中只有一套寄存器,为什么图2-12中寄存器集合按每个线程中的内容列出而不是按每个进程中的内容列出?
当一个线程停止时,它在寄存器中有值。它们必须被保存,就像进程停止时,必须保存寄存器。多线程和多进程没有什么不同,所以每个线程需要自己的寄存器保存区。
15、在没有时钟中段的系统中,一个县城放弃CPU后可能再也不会获得CPU资源,那么为什么线程还要通过thread_yield自愿放弃CPU?
进程中的线程合作。它们彼此不敌对。如果应用程序需要阻塞以运行得更好,那么一个线程可以调用thread_yield自愿放弃CPU。毕竟,同一个进程中的线程的全部代码通常是一个程序员写的。
16、线程可以被时钟中断抢占吗?如果可以,在什么情况下可以?如果不可以,为什么不可以?
17、请对使用单线程服务器和多线程服务器读取文件进行比较。假设所需要的数据都在块高速缓存中,花费15ms获得工作请求,分派工作,并处理其余必要工作。如果在三分之一时间时,需要一个磁盘操作,要另外花费75ms,此时该线程进入睡眠。在单线程情形下服务器每秒钟可以处理多少个请求?如果是多线程呢?
在单线程情况下,cache命中需15ms,cache未命中需要90ms。其加权平均为2/315+1/390。因此,平均请求为40ms,而服务器每秒可处理25个。对于多线程服务器,所有磁盘等待都是重叠的,因此每个请求都耗时15ms,而服务器每秒可处理66.6666个请求。
18.在用户空间实现线程,其最大的优点是什么?最大的缺点是什么?
最大的优势就是效率。不需要陷入内核来切换线程。最大的缺点是,如果一个线程阻塞,整个进程都会阻塞。
19、在图2-15中创建线程和线程打印消息是随机交织在一起的。有没有方法可以严格按照以下次序运行:创建线程1,线程1打印消息,线程1结束,创建线程2,线程2打印消息,线程2结束,以此类推;如果有,是什么方法,如果没有请解释原因。
是的,这是可以做到的。每次执行pthread_create后,主程序可以调用pthread_join等待刚刚创建的线程退出后再创建下一个线程。
20、在讨论线程中的全局变量时,曾使用过程create_global将存储分配给指向变量的指针,而不是变量自身。这是必需的,还是由于该过程也需要使用这些值?
指针是确实必要的,因为全局变量的大小是未知的。它可能是从字符到浮点数数组的任何类型。如果保存其值,就不得不把其大小传递给create_global,这都没有问题,但是必须将其类型作为set_global的第二个参数,那么read_global返回值的类型是什么呢。
21、考虑一个线程线程全部在用户空间实现的系统,该运行时系统每秒钟得到一个时钟中断。假设在该运行时系统中,当某个线程正在执行时发生一个时钟中断,此时会出现什么问题?你有什么解决该问题的建议吗?
答:runtime系统可以正好在这一时刻阻塞或者解除阻塞某个线程,并且忙于处理调度队列。此时并不适合于时钟中断处理程序开始检查该队列是否应该进行线程切换,因为它们可能处于不一致的状态。解决方法可以是:当进入runtime系统后,设置一个标志。时钟处理程序将看到该标志,并且设置其自己的标志,然后返回。当runtime系统完成时,它将检测时钟标志,看是否有时钟中断发生,并且现在运行时钟处理程序。
22、假设一个操作系统中不存在类似于select的系统调用来提前了解在从文件、管道或设备中读取时是否安全,不过该操作系统确实允许设置报警时钟,以便中断阻塞的系统调用。在上述条件下,是否有可能在用户空间中实现一个线程包?请讨论。
这是可能的,不过效率很低。线程想要做一个系统调用,首先设定警报定时器,然后才执行调用。如果线程阻塞,定时器将控制归还给线程包。当然,大多数调用是不阻塞的,而定时器必须被清除。每个可能被阻塞的系统调用都必须作为3个系统调用来执行。如果定时器过早失效,各种问题都可能发生。用这种方法建立线程包并不好。
23、两个进程在一个共享内存的多处理器(两个CPU)上运行,当他们要共享一块内存是,图2-23中按使用turn变量的忙等待解决方案还有效吗?
是的,它仍然有效,但当然还在忙着等待。
24、在抢占式进程调度的条件下,图2-24中互斥问题的Peterson解法可行吗?如果是非抢占式呢?
它肯定适用于抢占式调度。 实际上,它是为那种情况而设计的。 当调度是非抢占式时,它可能会失败。 考虑转弯最初为0但过程1首先运行的情况。 它将永远循环,永远不会释放CPU。
25、在2.3.4节中所讨论的优先级反转问题是否可能在用户级线程中发生?为什么?
当低优先级进程位于其临界区,而高优先级进程就绪并且被调度时,将发生优先级倒置问题。如果使用忙等待,高优先级进程将一直运行。对于用户级线程,不可能发生低优先级线程突然被剥夺而允许高优先级线程运行,因为是不可剥夺的。而内核级线程,就会出现这个问题。
26、在2.3.4节中,描述了一种有高优先级进程H和低优先级进程L的情况,导致了H陷入死循环。若采用轮转调度算法而不是优先级调度算法,还会发生这样问题吗?请给予讨论。
答:在轮转调度算法下。L迟早会运行,最终它将会离开临界区。关键是,在优先级调度算法下,L永远不会运行;循环,它定期得到一个正常的时间片,所以有机会离开其临界区。
27、在使用线程的系统中,若使用用户级线程,是每个线程一个堆栈还是每个进程一个堆栈?如果使用内核级线程倩况又如何呢?请给予解释。
答:每个线程都是自己调用例程,因此它必须有其自己的堆栈以保存局部变量、返回地址等等。这一点用户级线程和内核级线程是一样的。
28、在开发计算机时,通常首先用一个程序模拟,一次运行一条指令,甚至多处理器也严格按此模拟。在类似于这种没有同时事件发生的情形下,会出现竞争条件吗?
答:是的。模拟计算机也可以是多道程序设计的。例如,在进程A运行时,它读取一些共享变量。然后发生了一个模拟时钟周期和进程B运行。它也读取相同的变量,然后对变量进行了加1操作。当进程A运行时,如果它也对变量进行了加1操作,就发生了竞争条件。
29、将生产者-消费者问题扩展成一个多生产者-多消费者的问题,生成(消费)者都写(读)一个共享的缓冲区,每个生产者消费者都在自己的线程中执行。图2-28中使用信号量的解法在这个系统中还可行吗?
是的,它会按原样运作。 在给定的时刻,只有一个生产者(消费者)可以向缓冲区添加(移除)一个项目。
30、答:该解决方案满足互斥,因为两个过程都不可能在其关键部分。 也就是说,当转为0时,P0可以执行其临界区,但不能执行P1。 同样,当转弯为1.但是,这假定P0必须先运行。 如果P1产生某些东西并将其放入缓冲区,那么当P0可以进入其临界区时,它会发现缓冲区为空并阻塞。 而且,该解决方案需要严格交替两个过程,这是不希望的。
31、一个可以屏蔽中断的操作系统如何实现信号量?
要执行信号量操作,操作系统首先禁用中断。 然后它读取信号量的值。 如果它正在执行down并且信号量等于零,则它将调用进程放在与信号量关联的阻塞进程列表中。 如果它正在执行,它必须检查信号量是否阻止任何进程。 如果阻止了一个或多个进程,则会从阻塞进程列表中删除其中一个进程并使其可运行。 完成所有这些操作后,可以再次启用中断。
32、请说明仅通过二元信号量和普通机器指令如何实现计数信号量(即可以保持一个任意值得信号量)
将每个计数信号量与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操作。
33、如果一个系统只有两个进程,可以使用一个屏障来同步这两个进程吗?为什么?
答:如果程序操作按阶段执行,直到两个进程都完成当前阶段才能进入下一阶段,这时就应该使用屏障。
34、如果线程在内核中实现,可以使用内核信号量对同一个进程中的两个线程进行同步吗?如果线程在用户空间实现呢?假设在其他进程中没有线程必须访问该信号量。请讨论你的答案。
答:对于内核线程,线程可以在信号量上阻塞,而内核可以运行该进程中的其它线程。因而,使用信号量没有问题。而对于用户级线程,当某个线程在信号量上阻塞时,内核将认为整个进程都被阻塞,而且不再执行它。因此,进程失败。
35、管程内的同步机制使用条件变量和两个特殊操作wait和signal,一种更通用的同步形式是只用一条原语waituntil,它以任意的布尔谓词作为参数。例如
waituntilx < 0 or y + z < n
这样就不再需要signal原语。很显然这一方式比Hoare或Brinch Hansen方案更通用,但它从未被采用过。为什么?提示:请考虑其实现。
答:其实现的代价很高。 每次在某些等待变化的进程的谓词中出现的任何变量, runtime系统都必须重新计算该谓词,以判断该进程是否能够被解锁。而对于 Hoare和Brinch Hansen管程,则只需signal原语即可唤醒进程。
36、一个快餐店有四类雇员:(1) 领班,接收顿客点的菜单;(2)厨师,准备饭菜;(3)打包工,将饭菜装在袋子里;(4) 收银员,将食品袋交给顾客并收钱。每个雇员可被看作一个进行通信的顺序进程。它们采用的进程间通信方式是什么?请将这个模型与UNIX中进程联系起来。
答:雇员之间通过消息传递进行通信:在该例中,消息为订单、食物和袋子。在UNIX中,该4个进程通过管道连接。
37、假设有一个使用信箱的消息传递系统,当向满信箱发消息或从空信箱收消息时,进程都不会阻塞,相反,会得到一个错误代码。进程响应错误代码的处理方式为一遍一遍地重试,直到成功为止。这种方式会导致竞争条件吗?
答:它不会导致竞争条件(不会丢失任何东西),不过它是完全的忙等待。
38、CDC 6600计算机使用一种称作处理器共享的有趣的轮转调度算法,它可以同时处理多达10个I/O进程。每条指令结束后都进行进程切换,这样进程1执行指令1,进程2执行指令2,以此类推。进程切换由特殊硬件完成,所以没有开销。如果在没有竞争的条件下一个进程需要T秒钟完成,那么当有n个进程共享处理器时完成一个进程需要多长时间?
答:它需要nT sec。
【【】】39、考虑以下C代码:
void main() {
fork();
fork();
exit();
}
程序执行时创建了多少子进程?
创建了三个流程。 在初始进程分叉之后,有两个进程在运行,即父进程和子进程。 然后他们每个人分叉,创建两个额外的过程。 然后所有进程退出。
39、答:创建了三个进程。 在初始进程分叉之后,有两个进程运行,父进程和子进程。 然后他们每个人都分叉,创造了两个额外的过程。 然后所有进程退出。
40、Round-robin调度算法一般需要维护一个就绪进程列表,每个进程在列表中只出现一次。如果某个进程在列表中出现两次会发生什么情况?什么情况下允许多次出现?
如果进程在列表中多次出现,则每个循环将获得多个量子。 这种方法可用于为更重要的进程提供更大的CPU份额。 但是当进程阻塞时,最好从可运行进程列表中删除所有条目。
41、是否可以通过分析源代码来确定进程是CPU密集型的还是I/O密集型的?如何能在运行时刻进行此项决定?
答:在简单的情况下是有可能通过看源代码来判断是否为 I/O 绑定的。例如,程序开始时,将其所有输入文件读入到缓冲器中,这种程序通常不是 I/O 绑定的;但是,对不同文件进行增量地读写(诸如编译程序)的问题很有可能是I/O绑定的。如果操作系统提供诸如 UNIX ps的命令,就可以得知被程序使用的CPU 时间的量,你能把这个时间量与整个的时间比较以判断。当然,最有意义就是你是系统中唯一的用户。
42、请说明在Round-robin调度算法中时间片长度和上下文切换时间是怎么互相影响的。
43、对某系统进行监测后表明,当阻塞在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。
44、有5个待运行作业,估计它们的运行时N分別是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.
45、有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分钟完成,平均为20分钟。如果作业按A->E的次序执行,则分别在第10,16, 18, 22和30分钟完成,因此,平均为19.2分钟。最后,最短作业优先调度的完成时间分别为第2, 6, 12, 20和30分钟,平均为14分钟。
46、运行在CTSS上的一个进程需要30个时间片完成。该进程必须被调入多少次,包括第一次(在该进程运行之前)?
答:第一次得到 1 个时间片。随后获得 2, 4, 8 和 15 个时间片,因此必须经过 5 次交换。
47、一个实时系统有2个周期为5ms的点化任务,每次任务的CPU时间是1ms, 还有一个周期为33ms的视频流,每次任务的CPU时间是11ms.这个系统是可调度的吗?
每个语音呼叫需要200个1毫秒或200毫秒的样本。 它们一起使用400毫秒的CPU时间。 视频需要11毫秒33 1/3次/秒,总共约367毫秒。 总和是每秒767毫秒的实时时间,因此系统是可调度的。
48、在上一题中,如果再加入一个视频流,系统还是可调度的吗?
另一个视频流每秒消耗367毫秒的时间,每秒实时总共1134毫秒,因此系统不可调度。
49、用a = 1/2的老化算法用来预测运行时间。先前的四次运行,从最老的一个到最近的一个,其运行时间分别是40ms,20ms,40ms和15ms。下一次的预测时间是多少?
答:预测值的顺序为40,30,35,所以下一次是25。(把前两个数据加一起,除以2,然后把结果和下一个数据加一起,除以2。)
50、一个软实时系统有4个周期时间,其周期分别为50ms,100ms,200ms和250ms。假设这4个事件分别需要35ms,20ms,10ms和x ms的CPU时间。保持系统可调度的最大x值是多少?
答:所使用的 CPU 的片断为 35/50 + 20/100 + 10/200 + x/250。为了使得进程可调度,必须是总和小于因此,x必须小于12.5ms。
51、在哲学家就餐问题中使用如下规则:编号为偶数的哲学家先拿他左边的叉子,再拿他右边的叉子;编号为奇数的哲学家先拿他右边的叉子再拿他左边的叉子。这条规则能否避免死锁?
是。 总会有至少一个免费的叉子和至少一个可以同时获得两个叉子的哲学家。 因此,不会有僵局。 您可以尝试N = 2,N = 3和N = 4,然后进行推广。
52、一个实时系统需要处理两个语音通信,每个运行5ms,然后每次突发消耗1ms CPU时间,加上25帧/秒的一个视频,每一帧需要20ms的CPU时间。这个系统是可调度的吗?
答:每个语音通信运行200次/秒,每次突发消耗1毫秒,所以每个语音通信需要200毫秒/秒或两个语音通信需要400毫秒/秒。视频运行25次/秒,每次使用了20毫秒的时间,总共为500毫秒/秒。它们一起消耗900毫秒/秒,所以还有时间剩余,系统是可调度的。
53、考虑一个系统,在这个系统中为了内核线程调度希望将策略和机制分离。请提出一个实现此目标的手段。
答:内核可以通过任何方式调度进程,但对于每个进程,严格按照进程的优先级顺序执行。通过让用户进程设置自己的优先级,让用户控制策略,而内核处理机制。
54、在哲学家就餐问题的解法 (图2-46)中,为什么在过程 take_forks中将状态变量置为HUNGRY?
答:如果某个哲学家阻塞,其邻居稍后能够在test中检测其状态,发现他已经饥饿,当叉子可用时,就可以唤醒他了。
55、考虑图2-47中的过程pm_forks,假设变量state[i]在对test的两次调用之后而不是之前被置为THINKING,这个改动会对解法有什么影响?
答:该变化将意味着在哲学家停止进餐后,他的邻居都不能接着被选择。事实上,他们永远不会被选择。假设哲学家2完成了进餐,他将为哲学家1和3运行test,而两者都不会被启动,即使他们两个都饿了而且两个叉子都是可用的。类似的,如果哲学家4完成进餐,哲学家3也不会被启动。他将无法启动。
56、按照哪一类进程何时开始,读者-写者问题可以有若干种方式求解。请详细描述该问题的三种变体,每一种变体偏好(或不偏好)某一类进程。对每种变体,请指出当一个读者或写者访问数据库时会发生什么,以及当一个进程结束对数据库的访问后又会发生什么?
答:变种1:读者优先。当读者活跃时,写者都无法启动。当一个新的读者出现时,它可以立即开始除非当前有写者是活跃的。当写者完成时,如果有读者在等待,他们全都启动,无论是否有写者存在。
变种2:写者优先。当有写者等待时,读者都不会开始。当最后活跃的进程结束,如果有作者,就启动它;否则,所有读者(如果有)全部开始。
变种3:平衡的版本。当有读者是活跃的,新的读者可以立即开始。当写者完成时,新的写者优先,如果有写者等待的话。也就是说,一旦开始读,就一直读到没有读者为止。同样地,一旦开始作,所有挂起的写者都被允许运行。
57、请编写一个shell脚本,通过读取文件的最后一个数字,对之加1,然后再将该数字附在该文件上,从而生成顺序数文件。在后台和前台分別运行该脚本的一个实例,每个实例访问相同的文件。需要多长时间才出现竞争条件?临界区是什么?请修改该脚本以避免竞争(提示:使用In file file.lock锁住数据文件。)
答:一个可行的shell脚本应该如下:
if [ ! –f numbers ]; then echo 0 > numbers; fi
count=0
while (test $count != 200 )
do
count=‘expr $count + 1’
n=‘tail –1 numbers’
expr $n + 1 >>numbers
done
同时运行该脚本两次,通过后台启动它一次(使用)和再次在前台启动。然后检查文件编号。它可能开始看起来会像数字的有序列表,但在某一时刻,由于运行脚本的两个副本而创建的竞争条件,它就失去了它的规律。通过对脚本的每一个副本测试,并在进入关键区域之前设置一个锁,在离开关键区域时打开它,可以避免竞争。可以这样做:
if ln numbers numbers.lock
then
n=‘tail –1 numbers’
expr $n + 1 >>numbers
rm numbers.lock
fi
此版本只是当文件无法访问时直接跳过,不同的解决方案可以让进程休眠,忙等待,或仅仅循环计数,使得操作成功。
58、假设有一个提供信号量的操作系统。请实现一个消息系统,编写发送和接收消息的过程。
答:略。
59、使用管程而不是信号量来解决哲学家就餐题。
答:略。