现代操作系统第二章进程与线程习题1. 图2-2中给出了三个进程状态,在理论上,三个状态可以有六种转换,每个状态两个。
但是,图中只给出了四种转换。
有没有可能发生其他两种转换中的一个或两个?A:从阻塞到运行的转换是可以想象的。
假设某个进程在I/O上阻塞,而且I/O 结束,如果此时CPU空闲,该进程就可以从阻塞态直接转到运行态。
而另外一种转换(从阻塞态到就绪态)是不可能的。
一个就绪进程是不可能做任何会产生阻塞的I/O或者别的什么事情。
只有运行的进程才能被阻塞。
2.假设要设计一种先进的计算机体系结构,它使用硬件而不是中断来完成进程切换。
CPU需要哪些信息?请描述用硬件完成进程切换的工作过程。
A:应该有一个寄存器包含当前进程表项的指针。
当I/O结束时,CPU将把当前的机器状态存入到当前进程表项中。
然后,将转到中断设备的中断向量,读取另一个过程表项的指针(服务例程),然后,就可以启动这个进程了。
3.当代计算机中,为什么中断处理程序至少有一部分是用汇编语言编写的?A:通常,高级语言不允许访问CPU硬件,而这种访问是必需的。
例如,中断处理程序可能需要禁用和启用某个特定设备的中断服务,或者处理进程堆栈区的数据。
另外,中断服务例程需要尽快地执行。
(补充)主要是出于效率方面的考量。
中断处理程序需要在尽量短的时间内完成所需的必要处理,尽量减少对线程/程序流造成的影响,因此大部分情况下用汇编直接编写,跳过了通用编译过程中冗余的适配部分。
4.中断或系统调用把控制转给操作系统时,为什么通常会用到与被中断进程的栈分离的内核栈?A:内核使用单独的堆栈有若干的原因。
其中两个原因如下:首先,不希望操作系统崩溃,由于某些用户程序不允许足够的堆栈空间。
第二,如果内核将数据保留在用户空间,然后从系统调用返回,那么恶意的用户可能使用这些数据找出某些关于其它进程的信息。
5.一个计算机系统的内存有足够的空间容纳5个程序。
这些程序有一半的时间处于等待I/O的空闲状态。
请问CPU时间浪费的比例是多少?A:^5 =%6.一个计算机的RAM有4GB,其中操作系统占512MB。
所有进程都占256MB(为了简化计算)并且特征相同。
要是CPU利用率达到99%,最大I/O等待是多少?A:内存中最多可放(4GB-512MB)/256MB=14个进程,设每个进程的I/O等待占总运行时间的比例为p,则CPU利用率=1-p^14>99%====>p<%7.多个作业能够并行运行,比它们顺序执行完成的要快。
假设有两个作业同时开始执行,每个需要20分钟的CPU时间。
如果顺序执行,那么最后一个作业需要多长时间可以完成?如果并行执行又需要多长时间?假设I/O等待占50%。
A: 每个进程的时间为40min。
顺序执行时,最后一个作业需要80min才能完成。
并行执行时,cpu利用率为1-p^n = 75%, cpu计算时间为40min,故总时间t=40/75%=8.考虑一个6级多道程序系统(内存中可同时容纳6个程序)。
假设每个进程的I/O等待占40%,那么CPU利用率是多少?A:利用率=1-p^n=1-^6 = =%9.假设要从互联网上下载一个2GB大小的文件,文件内容可以从一组镜像服务器获得,每个服务器可以传输文件的一部分。
假设每个传输请求给定起始字节和结束字节。
如何用多线程优化下载时间?A:客户端进程可以创建单独的线程; 每个线程都可以从其中一个镜像服务器获取文件的不同部分。
这有助于减少停机时间。
当然,所有线程都共享一个网络链接。
这个链接可以成为一个瓶颈,因为线程的数量变得非常大。
10.为什么图2-11a的模式不适合用于在内存使用高速缓存的文件服务器?每个进程可以有自己的高速缓存吗?A:即使是有可能实现,也是很难保持文件系统的一致性。
假设某个客户进程给服务器进程1发送请求要更新文件。
该进程更新其内存的cache项。
然后,另一个客户进程给服务器进程2发送请求读取该文件。
不幸的是,如果该文件还在 cache中,服务器进程2对此毫不知情,将返回过时的数据。
如果第一个进程在缓冲后将文件写到磁盘中,而服务器进程2每次读取时检查磁盘其缓存的备份是否是最新的,系统还可以工作,但是需要避免磁盘访问的所有缓存系统。
(个人认为,高速缓存应该每个进程共享,因为不是每个进程都需要频繁读写数据,如果每个进程都分配cache会造成资源浪费。
)11.当一个多线程进程创建子进程时,如果子进程复制父进程的所有线程,就会出现问题:假如夫进程中有一个线程正在等待键盘输入,现在就有两个线程在等待键盘输入,父进程和子进程各有一个。
这种问题在单线程进程中也会发生吗?A:不会。
如果单线程进程在键盘上阻塞,就不能创建子进程。
(而多线程进程在一个线程阻塞时可以运行另一个线程,整个进程不会因此被阻塞。
)12.在图2-8中,给出了一个多线程Web服务器。
如果读取文件的惟一途径是正常的阻塞read系统调用,那么Web服务器应该使用用户级线程还是内核级线程?为什么?A:当工作者线程从磁盘读取Web页时,它就会被阻塞。
如果使用用户级线程,该动作将阻塞整个进程,而破坏多线程的价值。
这就是使用内核线程的原因:某些线程的阻塞不会影响到其他线程。
13.在本章中,我们介绍了多线程Web服务器,说明它比单线程服务器和有限状态机服务器更好的原因。
存在单线程服务器更好一些的情形吗?请举例。
A:在多线程Web服务器中,由分派程序从网络中读入工作请求,在检查请求后,分派线程挑选一个空转的(即被阻塞的)工作线程,提交该请求。
在工作线程被唤醒后,他检查有关的请求是否在Web页面高速缓存中,这个高速缓存是所有线程否可以访问的。
如果没有,该线程开始一个从磁盘调入页面的read操作,并且阻塞知道该磁盘操作完成。
在上述线程被阻塞在磁盘操作上时,分派线程可能挑选另一个线程运行,可以有效利用CPU资源。
而在单线程服务器上,只能等第一个线程完成后,才能开始第二个线程。
也存在单线程服务器更好的情形。
如果服务器是完全CPU绑定的,则不需要多线程。
这只会增加不必要的复杂性。
假设某个百万人口区域的电话查号系统(类似于114),如果每个(姓名,电话号码)记录为64个字符,整个的数据库则为64MB,这就很容易全部读入服务器内存中以提供快速的查询。
14。
既然计算机中只有一套寄存器,为什么在图2-12中的寄存器集合是按每个线程中列出而不是按每个进程列出。
A:当一个线程停止时,它在寄存器中有值。
它们必须被保存,就像进程停止时,必须保存寄存器。
多线程和多进程没有什么不同,所以每个线程需要自己的寄存器保存区。
15.在没有时钟中断的系统中,一个线程放弃CPU后可能再也不会获得CPU资源,那么为什么线程还要通过调用thread_yield自愿放弃CPU?A:进程中的线程合作。
它们彼此不敌对。
如果应用程序需要阻塞以运行得更好,那么一个线程可以调用thread_yield自愿放弃CPU。
毕竟,同一个进程中的线程的全部代码通常是一个程序员写的。
16.线程可以被时钟中断抢占吗?如果可以,在什么情形下可以?如果不可以,为什么不可以?A:用户级线程不能被时钟剥夺,除非整个进程的时间片用完。
内核级线程可以单独地被剥夺。
在后一种情况下,如果线程运行过久,时钟将中断该当前进程,因而当前线程也被中断。
内核可以自由地从同一个进程中选取其他线程运行。
17.请对使用单线程文件服务器和多线程文件服务器读取文件进行比较。
假设所需要的数据都在块高速缓存中,获得工作请求,分派工作,并处理其余必要工作需要花费12ms。
如果在时间过去1/3时,需要一个磁盘操作,额外花费75ms,此时该线程进入睡眠。
单线程服务器每秒钟可以处理多少个请求?多线程服务器呢?A:在单线程情况下,cache命中需要12ms,cache未命中需要87ms,其加权平均为2/3·12+1/3·87 = 37 ms,一秒钟可以完成1s/37ms = 27个. 在多线程情况下,所有磁盘等待都是重叠的,因此每个请求耗时12ms,一秒钟可以完成1s/12ms = 个(个人认为这样算不太准确,因为最后的几个线程如果cache未命中的话,就需要87ms,可能是完不成的,不过这个题意翻译的不是很清楚,什么叫做“时间过去1/3时”,估计原意应该是”有1/3的时间需要额外的磁盘操作“。
这样平均算下来也可以忽略cache未命中发生的分布情况。
)18.在用户态实现线程的最大的优点是什么?最大的缺点是什么?A:最大的优势就是效率。
不需要陷入内核来切换线程。
最大的缺点是,如果一个线程阻塞,整个进程都会阻塞。
19.在图2-15中创建线程和线程打印消息是随机交织在一起的。
有没有方法可以严格按照以下次序运行:创建线程1,线程1打印消息,线程1结束,创建线程2,线程2打印消息,线程2结束,以此类推;如果有,是什么方法,如果没有请解释原因。
A:是的,这是可以做到的。
每次执行pthread-create后,主程序可以调用pthread_join等待刚刚创建的线程退出后再创建下一个线程。
20.在讨论线程中的全局变量时,曾使用过程create_global将存储分配给指向变量的指针,而不是变量自身。
这是必需的吗?还是直接使用变量自身也可行?A:将存储分配给指针是确实必要的,因为全局变量的大小是未知的。
它可能是从字符到浮点数数组的任何类型。
如果保存其值,就不得不把其大小传递给create_global,这都没有问题,但是必须将其类型作为set_global的第二个参数,那么read_global返回值的类型是不确定的。
21.考虑一个线程全部在用户态实现的系统,该运行时系统每秒钟获得一个时钟中断。
当某个线程正在运行时系统中执行时发生一个时钟中断,此时会出现什么问题?你有什么解决该问题的建议吗?A:runtime系统可以正好在这一时刻阻塞或者解除阻塞某个线程,并且忙于处理调度队列。
此时并不适合于时钟中断处理程序开始检查该队列是否应该进行线程切换,因为它们可能处于不一致的状态。
解决方法可以是:当进入runtime 系统后,设置一个标志。
时钟处理程序将看到该标志,并且设置其自己的标志,然后返回。
当runtime系统完成时,它将检测时钟标志,看是否有时钟中断发生,并且现在运行时钟处理程序。
22.假设一个操作系统中不存在类似于select的系统调用来提前了解在从文件、管道或设备中读取时是否安全,不过该操作系统确实允许设置报警时钟,以便中断阻塞的系统调用。
在上述条件下,是否有可能在用户态中实现一个线程包?请讨论。
A:这是可能的,不过效率很低。
线程想要做一个系统调用,首先设定警报定时器,然后才执行调用。
如果线程阻塞,定时器将控制归还给线程包。