也就是说,A产品的数量不能比B产品的数量少N个以上,A产品的数量不能比B产品的数量多M个以上. 解;在本题中,我们可以设置两个信号量来控制A、B产品的存放数量,sa表示当前 允许A产品比B产品多入库的数量,即在当前库存量和B产品不入库的情况下,还可以允 许sa个A产品入库;sb表示当前允许B产品比A产品多入库的数量,即在当前库存量和 A产品不入库的情况下,还可以允许sb个B产品入库。初始时,sa为M一1,sb为N一1,当往库中存放入一个A产品时,则允许存入B产品的数量也增加1;当往库中存放入一个B产品时,则允许存入A产品的数量也增加1。
产品A、B的入库过程描述如下: int mutex=1; /*互斥信号量*/ int sa=M-1; int sb=N-1; main( ) {
while(1) {
取一个产品;
if(取的是A产品) {
p(sa); p(mutex); 将产品入库; v(mutex); v(sb): }
else /*取的产品是B*/ {
p(sb);
p(mutex); 将产品入库; v(mutex); v(pa); } } }
从本题的解法可以看出,当有比较复杂条件出现时,可以把复杂条件分解成一组简单条件,这样就能很容易地写出对应的程序流程了。
十六、(南开大学1997年试题)在南开大学和天津大学之间有一条弯曲的小路,其中从S到T一段路每次只允许一辆自行车通过,但其中有一个小的安全岛M(同时允许两辆自行车停留),可供两辆自行车已从两端进入小路情况下错车使用,如图2.14所示。试设计一个算法使来往的自行车均可顺利通过。p53 《 错 》
[分析及相关知识] 在本题中,需要控制路段T到L,路段S到K及安全岛M的使用。路段T到L及路段S到K同时只允许一辆自行车通过,而安全岛M允许两辆自行车使用,因此可以用三个信号量来管理它们。另一方面,同一方向上的自行车最多只能有一辆通过这段路(两个方向上有两辆),因此还应该用两个信号量来控制.
解:在本题中,应设置5个信号量ST,TS,K,L,M,信号量ST表示是否允许自行
车从南开大学去天津大学,其初值为1;信号量TS表示是否允许自行车从天津大学去南开 大学,其初值为1;信号量K表示是否允许自行车通过路段S到K,其初值为1;信号量L表示是否允许自行车通过路段T到L,其初值为1;信号量M表示安全岛上还可停放自行车的数目,其初值为2。其控制过程描述如下: int ST=1; int TS=1;
int K=1; int L=1; int M=2;
totian( ) /*从南开大学去天津大学*/ {
p(ST); p(K);
从S走到K; p(M);
进入安全岛; v(K); p(L);
从L走到T; v(M); v(L); v(ST); }
tonan() /*从天津大学去南开大学*/ {
p(TS); p(L); 从T走到L; p(M);
进入安全岛; v(L); p(K);
从K走到S; v(M); v(K); v(TS); }
另一题 在南开大学和天津大学之间有一条弯曲的小路,其中从S到T一段路每次只允许一辆自行车通过,但中间有一个小的“安全岛”M(同时允许两辆自行车停留),可供两辆自行车已从两端进入小路情况下错车使用,如图
3-28所示。试设计一个算法使来往的自行车均可顺利通过。L3.46 p129 《正确》
[解答]
由于小路中间的安全岛M仅允许两辆自行车停留,本应该作为临界资源而设置信号量,
但仔细分析可以发现:在任何时刻进入小路的自行车最多不会超过两辆(南开和天大方向各一辆),因此,无需为安全岛M设置信号量。在路口S处,南开出发的若干自行车应进行进入小路权的争夺,以决定谁能够进入小路SK段,为此,设置信号量S(初值为1)来控制南
开路口资源的争夺。同理,设置信号量T(初值为1)来控制天大路口资源的争夺。此外,
小路SK段仅允许一辆自行车通过,所以设置信号量SK(初值为1)来进行控制,而对于LT
段则设置信号量LT(初值为1)进行控制。 begin
S:=1;T:=1; SK:=1;LT:=1; cobegin
进程i (i为南开方向的自行车,i=1,2,…): begin
P(S); /*与其他南开方向的自行车争夺路口S的使用权*/
P(SK); /*同对面(天大)来的自行车争夺SK路段的使用权*/
通过SK路段; 进入安全岛M; V(SK); /*一旦进入安全岛M便可释放路段SK的使用权*/
P(LT); /*同对面(天大)来的自行车争夺LT路段的使用权*/
通过LT路段:
V(LT); /*已通过LT路段,释放路段LT的使用权*/
V(S) /*已经通过小路,则允许在路口S等待的自行车争夺再次进入S的 使用权*/ end;
进程j (j为天大方向的自行车,j=1,2,…): begin
P(T); /*与其他天大方向的自行车争夺路口T的使用权*/
P(LT); /*同对面(南开)来的白行车争夺LT路段的使用权*/
通过LT路段; 进入安全岛M; V(LT): /*—旦进入安全岛M便可释放路段LT的使用权*/
P(SK): /*同对面(南开)来的自行车争夺SK路段的使用权*/
通过SK路段:
V(SK); /*已通过SK路段,释放路段SK的使用权*/
V(T) /*已经通过小路,则允许在路口 T等待的臼行车争夺再次进 入T的使用权*/ end coend end;
注意:如果在进程i进入安全岛M后,在释放路段SK的同时释放了路口S,而此时进程i
也进入安全岛,同样在释放路段LT的同时释放路口T,那么,南开、天大方向将各有一自行车又进入路段SK和路段LT,这使得在安全岛M中的两辆自行车都无法继续前进,而在SK路段和LT路段的—自行车也无法进入安全岛M,从而造成死锁。因此,进程i在进入安全岛M后是为对面<天大)来的自行车释放路段SK的使用权,而进程j在进入安全岛M后也是为对面(南开)来的自行车释放路段LT的使用权。 十七、(中国科学院软件研究所1995年试题)多个进程共享一个文件,其中只读文件的
称为读者,只写文件的称为写者。读者可以同时读,但写者只能独立写。请:
①说明进程间的相互制约关系,应设置哪些信号量? ②用P、V操作写出其同步算法。
③修改上述的同步算法,使得它对写者优先,即一旦有写者到达,后续的读者必须等 待。而无论是否有读者在读文件。
解:本题前两问是经典读者写者问题,第三问对读者写者问题加了一些限制,即使算 法对写者优先。
①进程间的相互制约关系有三类:一是读者之间允许同时读;二是读者与写者之间须 互斥;三是写者之间须互斥。 为了解决读者、写者之间的同步,应设置两个信号量和一个共享变量;读互斥信号量 rmutex,用于使读者互斥地访问共享变量count,其初值为1;写互斥信号量wmutex,用于实现写者与读者的互斥及写者与写者的互斥,其初值为1;共享变量count,用于记录当前正在读文件的读者数目,初值为0。
②进程间的控制算法如下所示: int rmutex=l; int wmutcx=l; int count=0; main( ) {
cobegin
reader( ); writer( ); coend }
reader( ) {
while (1) {
p(rmutex);
if(count=0) p(wmutex); /*当第一个读者读文件时,阻止写者写*/ count++; v(rmutex); 读文件; p(rmutex);
count --;
if(coun==)v(wmutex); /*当最后一个读者读完文件时,允许写者写*/ v(rmutex); } }
writer( ) {
while(1) {
p(wmutex); 写文件; v(wmutex); } }
③为了提高写者的优先级,增加一个信号量s,用于在写进程到达后封锁后续的读者。 其控制流程如下: int rmutex=1; int wmutex=l; int count=0; int s=1; main() {
cobegin reader(); writer(); coend }
reader() {
while (1) {
p(s);
p(rmutex);
if(coun==0) p(wmutex); /*当第一个读者读文件时,阻止写者写*/ count++;
v(rmutex); v(s); 读文件; p(rmutex); count--;
if(count==0)v(wmutex); /*当最后一个读者读完文件时,允许写者写*/ v(rmutex); } }
writer() {
while(1) {
p(s); p(wmutex); 写文件; v(wmutex); v(S); } }
十八、既考虑作业等待时间,又考虑作业执行时间的调度算法是_____ 。
A. 响应比高者优先 B.短作业优先 p91 C.优先级调度 D.先来先服务
答:A
十九、______是指从作业提交给系统到作业完成的时间间隔。p91
A.周转时间 B.响应时间 C. 等待时间 D.运行时间 答:A
二十、作业从进入后备队列到被调度程序选中的时间间隔称为_____。p91
A.周转时间 B.响应时间 C. 等待时间 D.触发时间 答:C
二十一、假设下述四个作业同时到达,当使用最高优先数优先调度算法时,作业的平均周转时间为_____小时。 P91
作业 所需运行时间 优先数
1 2 4 2 5 9 3 8 1 4 3 8
A.4.5 B.10.5 C.4.75 D.10.25 答:D
二十二、系统在______,发生从目态到管态的转换。P92
A. 发出P操作时 B.发出V操作时
C.执行系统调用时 D. 执行置程序状态字时 答:C 二十三、操作系统为用户提供两个接口。一个是__①__,用户利用它来组织和控制作业的执行或管理计算机系统。另一个是__②__,编程人员使用它们来请求操作系统提供服务。p92
答:①命令接口 ②程序接口
二十四、设有一组作业,它们的提交时间及运行时间如下:p93
作业号 提交时间 运行时间(分钟) 1 9:00 70 2 9:40 30 3 9:50 10 4 10:10 5
在单道方式下,采用短作业优先调度算法,作业的执行顺序是___。 答:1、4、3、2
二十五、设有4道作业,它们的提交时间及执行时间如下:p93
作业号 提交时间 执行时间 1 10.0 2.0 2 10.2 1.0 3 10.4 0.5 4 10.5 0.3
试计算在单道程序环境下,采用先来先服务调度算法和最短作业优先调度算法时的平均周转时间和平均带权周转时间,并指出它们的调度顺序。(时间单位:小时,以十进制进行计算。)
解:若采用先来先服务调度算法,则其调度顺序为1、2、3、4。
作业号 提交时间 执行时间 开始时间 完成时间 周转时间 带权周转时间
1 10.0 2.0 10.0 12.0 2.0 1.0 2 10.2 1.0 12.0 13.0 2.8 2.8 3 10.4 0.5 13.0 13.5 3.1 6.2 4 10.5 0.3 13.5 13.8 3.3 11.0 平均周转时间 T=(2.0+2.8+3.1+3.3)/4=2.8 平均带权周转时间 W=(1+2.8+6.2+11)/4=5.25
若采用短作业优先调度算法,则其调度顺序为1、4、3、2。
作业号 提交时间 执行时间 开始时间 完成时间 周转时间 带权周转时间
1 10.0 2.0 10.0 12.0 2.0 1.0 4 10.5 0.3 12.0 12.3 1.8 6.0 3 10.4 0.5 12.3 12.8 2.4 4.8 2 10.2 1.0 12.8 13.8 3.6 3.6 平均周转时间 T=(2.0+1.8+2.4+3.6)/4=2.45 平均带权周转时间 W=(1+6+4.8+3.6)/4=3.85 二十六、下表给出作业1、2、3的到达时间和运行时间。采用短作业优先调度算法和先来先服务调度算法,试问平均周
转时间各为多少?是否还有更好的调度策略存在?(时间单位:小时,以十进制进行计算。) p94 作业号 到达时间 运行时间 1 0.0 8.0 2 0.4 4.0 3 1.0 1.0
解:采用先来先服务调度策略,则调度顺序为1、2、3。 作业号 到达时间 运行时间 开始时间 完成时间 周转时间
1 0.0 8.0 0.0 8.0 8.0 2 0.4 4.0 8.0 12.0 11.6 3 1.0 1.0 12.0 13.0 12.0 平均周转时间T=(8+11.6+12)/3=10.53
采用短作业优先调度策略,则调度顺序为1、3、2。 作业号 到达时间 运行时间 开始时间 完成时间 周转时间
1 0.0 8.0 0.0 8.0 8.0 3 1.0 1.0 8.0 9.0 8.0 2 0.4 4.0 9.0 13.0 12.6 平均周转时间T=(8+8+12.6)/3=9.53
存在缩短平均周转时间的策略,如知道后面将来两个短作业,因此在作业1到达后暂不投入运行,等所有作业到齐后再按短作业优先调度算法调度,其调度顺序为3、2、1。 作业号 到达时间 运行时间 开始时间 完成时间 周转时间
3 1.0 1.0 1.0 2.0 1.0 2 0.4 4.0 2.0 6.0 5.6 1 0.0 8.0 6.0 14.0 14.0 平均周转时间T=(1+5.6+14)/3=6.87
二十七、假设有四个作业,它们的提交、运行时间如下表所示。若采用响应比高者优先调度算法,试问平均周转时间和平均带权周转时间为多少? (时间单位:小时,以十进制进行计算。) p95
作业号 到达时间 运行时间 1 8.0 2.0
2 8.3 0.5 3 8.5 0.1 4 9.0 0.4
[分析及相关知识] 所谓响应比高者优先调度算法,就是在每次调度作业运行 时,先计算后备作业队列中每个作业的响应比,然后匆匕选响应比最高者投入运行。 响应比定义如下:
响应比=作业响应时间/运行时间的估计值
其中响应时间为作业进入系统后的等待时间加上估计的运行时间。于是
响应比=1+作业等待时间/运行时间的估计值
在8:00时,因为只有作业1到达,系统将作业1投入运行。作业1运行2小时(即
10:00时)完成。由于该算法采用响应比高者优先调度算法,这样在作业1执行
完后,要计算剩下三个作业的响应比,然后选响应比高者去运行。剩下三个作业 的响应比为:
r2=l+(10.0-8.3)/0.5=4.4 r3=l+(10.0-8.5)/0.1=16 r4=l+(10.0-9.0)/0.4=3.5
从计算结果看,作业3的响应比高,所以让作业3先运行。作业3运行0.1小时
完成(即10:10时),此时,作业2和作业4的响应比为: r2=l+(10.1-8.3)/0.5=4.6 r4=l+(10.1-9.0)/0.4=3.75
从上述计算结果看,作业2的响应比高,所以让作业2先运行。因此四个作业的
执行次序为:作业1、作业3、作业2、作业4.
解:四个作业的调度次序为:作业1、作业3、作业2、作业4。
作业号 到达时间 运行时间 开始时间 完成时间 周转时间 带权周转时间
1 8.0 2.0 8.0 10.0 2.0 1.0
2 8.3 0.5 10.1 10.6 2.3 4.6 3 8.5 0.1 10.0 10.1 1.6 16.0 4 9.0 0.4 10.6 11.0 2.0 5.0 平均周转时间 T=(2.0+2.3+1.6+2.0)/4=1.975 平均带权周转时间 W=(1+4.6+16+5)/4=6.65
二十八、设有一组作业,它们的提交时间及运行时间如下所示。P101
作业号 到达时间 运行时间(分钟) 1 8:00 70 2 8:40 30 3 8:50 10 4 9:10 5
试问在单道方式下,采用响应比高者优先调度算法,作业的执行顺序是什么?
[分析及相关知识] 所谓响应比高者优先调度算法,就是在每次调度作业运行 时,先计算后备作业队列中每个作业的响应比,然后书也选响应比最高者投入运行。 响应比定义如下:
响应比=1+作业等待时间/运行时间
8:00时,因为这时只有作业1到达,因此调度作业1运行。70分钟后(即9:10), 作业1运行完毕。
9:10时,这时作业1运行完成,其他三个作业均已到达。它们的响应比分别为: r2=1+(9:10—8:40)/30=2 r3=1+(9:10—8:50)/10=3 r4=1+(9:10—9:10)/5=1
从计算结果看,作业3的响应比高,所以让作业3先运行。10分钟后(即9:20), 作业3运行完毕.
9:20时,这时作业3运行完成,其他两个作业的响应比分别为:
r2=1+(9:20—8:40)/30=2.3 r4=1+(9:20—9:10)/5=3
从计算结果看,作业4的响应比高,所以让作业4先运行。5分钟后(即9:25),
作业4运行完毕.这时只剩下作业2,调度作业2运行。 解:从上面的分析可知,作业的执行顺序为1、3、4、2。 二十九、在虚拟存储系统中,若进程在内存中占3块(开始时为空),采用先进先出页面淘汰算法,当执行访问页号序列为1、2、3、4、1、2、5、1、2、3、4、5、6时,将产生____次缺页中断。P121
A.7 B.8 C.9 D.10 答:D
三十、分区管理中采用“最佳适应”分配算法时,宜把空闲区按_____次序登记在空闲区表中。P122 A. 长度递增 B.长度递减 C. 地址递增 D.地址递减 答:A
三十一、已知页面走向为1、2、1、3、1、2、4、2、1、3、4,且开始执行时主存中没有页面。若只给该作业分配2个物理块,当采用FIFO页面淘汰算法时缺页率为多少?假定现有一种淘汰算法,该算法淘汰页面的策略为当需要淘汰页面时,就把刚使用过的页面作为淘汰对象,试问就相同的页面走向,其缺页率又为多少? p126
[分析及相关知识] 在进行内存访问时,若所访问的页已在主存,则称此次访问成功;若所访问的页不在主存,则称此次访问失败,并产生缺页中断。若程序P在运行过程中访问页面的总次数为s,其中产生缺页中断的访问次数为f,则其缺页率为:f/s。
解:根据所给页面走向,采用FIFO淘汰算法的页面置换情况如下:
页面走向 1 2 1 3 1 2 4 2 1 3 4 物理块1 1 1 3 3 2 2 1 1 4 物理块2 2 2 1 1 4 4 3 3 缺页 缺 缺 缺 缺 缺 缺 缺 缺 缺
从上述页面置换图可以看出:页面引用次数为11次,缺页次数为9次,所以缺页率为9/11。
若采用后一种页面淘汰策略,其页面置换情况如下:
页面走向 1 2 1 3 1 2 4 2 1 3 4 物理块1 1 1 3 1 1 1 3 4 物理块2 2 2 2 4 2 2 2 缺页 缺 缺 缺 缺 缺 缺 缺 缺
从上述页面置换图可以看出:页面引用次数为11次,缺页次数为8次,所以缺页率为8/11。
三十二、有一请求分页存储管理系统,页面大小为每页100字节。有一个50x50的整型数
组按行连续存放,每个整数占两个字节,将数组初始化为0的程序描述如下:p129 int a[50][50]; int i,j;
for (i=0;i<=49;i++)
for (j=0;j<=49;j++) a[i][j]=0;
若在程序执行时内存中只有一个存储块用来存放数组信息,试问该程序执行时产生多少次缺页中断?
解:由题目可知,该数组中有2500个整数,每个整数占用2个字节,共需存储空间
5000个字节;而页面大小为每页100字节,数组占用空间50页。假设数据从该作业的第 m页开始存放,则数组分布在第m页到第m+49页中,它在主存中的排列顺序为:
a[0][0],a[0][ll,…,a[0][49] 第m页 a[1][0],a[1][1],…,a[1][49] 第m+l页
┇
a[49][0],a[49][1],…,a[49][49] 第m+49页
由于该初始化程序是按行进行的,因此每次缺页中断调进一页后,位于该页内的数组元素全部赋予0值,然后再调入下一页,所以涉及的页面走向为m,m+l,…,m+49,故缺页次数为50次。
三十三、在一分页存储管理系统中,逻辑地址长度为16位,页面大小为4096字节,现有一逻辑地址为2F6AH,且第0、1、2页依次存放在物理块5、10、11中,问相应的物理地址为多少? p137
解:由题目所给条件可知,本页式系统的逻辑地址结构为:
页号P 页内位移W 15 11 12 0
逻辑地址2F6AH的二进制表示如下:
页号P 页内位移W 0010 11101101010
由此可知逻辑地址2F6AH的页号为2,该页存放在第11号物理块中,用十六进制表
示块号为B,所以物理地址为BF6AH。 三十四、(南开大学1994年试题)在采用页式存储管理的系统中,某作业J的逻辑地址空间为4页(每页2048字节),且已知该作业的页面映象表(即页表)如下:p139 页号 块号 0 2 1 4 2 6 3 8
试借助地址变换图(即要求画出地址变换图)求出有效逻辑地址4865所对应的物理地址。
解:在本题中,一页大小为2048字节,则逻辑地址4865的页号及页内位移为; 页号 4865/2048=2
页内位移 4865-2048X2=769
然后,通过页表查知物理块号为6,将物理块号与逻辑地址中的页内位移拼接,形成物理地址,即: 6X2048+769=13057
其地址变换过程如图5.13所示。
三十五、中断矢量是指_________。P153 A. 中断处理程序入口地址 B.中断矢量表起始地址
C.中断处理程序入口地址在中断矢量表中的存放地址 D.中断断点的地址 答:A
三十六、用1s命令以长格式列目录信息时,若某一文件的特征在文件列表中按如下顺序显示在屏幕上:p242 8234 drwxrw-r-- 2user gk 3564 COT 1999 /user/asd.h 则同组人的访问权限是______。 A. 读和执行 B.读或执行 C. 写和执行 D.读和写 答:D
三十七、UNIX中显示文件内容用_____命令。p243 A.type B.cat C.dir D.more 答;B
三十八、指出下列左边的命令与右边所列的哪个功能相匹配。P243
(1)who (_①_) (2)passwd (_②_) (3)date (_③_) (4)cal (_④_) (5)su (_⑤_)
A.显示日期 B.显示日历
C.使自己成为特权用户 D. 显示哪些用户在使用系统
E.修改口令
答:①D ②E ③A ④B ⑤C
三十九、下列命令执行的结果是(以字母形式):p243 (1)chmod 755 filel (_①_) (2)chmod 664 file2 (_②_) (3)chmod 700 file3 (_③_) (4)chmod 644 file4 (_④_) A.rwxr-xr-x B.rw-rw-r- C.rwx------ D.rw-r-r-- 答:①A ②B ③C ④D
四十、假设当前目录为HOME目录,选择命令完成下列操作。P244
(1)列出该目录中所有文件和目录 (_①_) (2)读名为file2的文件 (_②_) (3)建立file2的一个副本,名为file5 (_③_) (4)建立一个子目录D2 (_④_) (5)转到子目录D2 (_⑤_) (6)把file2移到D2 (_⑥_)
(7)列出HOME中的所有文件 (_⑦_) (8)建立与D2同级的子目录D3 (_⑧_)
(9)在D3中为file2建立一个链接,名为file4 (_⑨_) (10)删除子目录D3 (_⑩_)
A.rm*;cd..;rmdir D3 B. cd D3;ln ../D2/file2 file4 C.cd..;mkdir D3 D.ls -la../* E.mv ../file2 F.cd D2
G.mkdir D2 H.cp file2 file5 I. cat file2或more file2 J.ls -la
答:①J ②I ③H ④G ⑤F ⑥E ⑦D ⑧C ⑨B ⑩A
四十一、在UNIX系统中运行下面程序,最多可产生多少个进程?画出进程家族树。P249 main() {
fork(); fork(); fork(); }
[分析及相关知识] 系统调用fork的功能是创建一个新进程,新进程运行与其创建者一样的程序,新创建的进程称为子进程,调用fork的进程称为父进程,父子进程都从fork调用后的那条语句开始执行。
当程序执行时,若所有进程都能成功地执行系统调用fork,则会产生最多数目的进程。为了描述方便起见,将开始执行时的进程称为A进程,此时程序计数器PC,指向第一个fork调用。 main() {
fork(); /* ←PC,进程A*/ fork(): fork(); }
当进程A成功地执行完第一个fork调用时,它创建了一个子进程,将此子进程称
为进程B。此时,进程A、B的程序计数器PC指向第二个fork调用,进程A派生 了1个子孙进程. main() {
fork():
fork(); /* ←PC,进程A*/ fork(); }
main()
{
fork();
fork(); /* ←PC,进程B*/ fork(); }
当进程A、B成功地执行完第二个fork调用时,它们分别创建了一个子进程,将
这些子进程分别称为进程C、D.此时,进程A、B、C、D的程序计数器PC指向第
三个fork调用,进程A派生了3个子孙进程。 main() {
fork(); fork();
fork(); /* ←PC,进程A*/ }
main() {
fork(); fork();
fork(); /* ←PC,进程B*/ }
main() {
fork(); fork();
fork(); /* ←PC,进程C*/ )
main() {
fork(); fork();
fork(); /* ←PC,进程D*/ )
当进程A、B、C、D成功地执行完第三个fork调用时,它们分别创建了一个子进
程,将这些子进程分别称为进程E、F、C、H.此时,进程A、B、C、D、E、F、C、
H的程序计数器PC指向程序结束处,进程A派生了7个子孙进程。 main() {
fork(); fork(); fork();
} /* ←PC,进程 main() {
fork(); fork(); fork();
) /* ←PC,进程 main() {
fork(); fork(): fork();
} /* ←PC,进程 main() {
fork(); fork(); fork();
} /* ←PC,进程 main() {
fork(); fork();
A*/ B*/ C*/ D*/ fork():
} /* ←PC,进程E*/ main() {
fork(); fork(); fork();
} /* ←PC,进程F*/ main() {
fork(); fork(); fork();
) /* ←PC,进程G*/ main() {
fork(); fork(); fork();
} /* ←PC,进程H*/
进程家族树是一棵有向树,有向树的节点代表进程,由进程P指向进程Q的边表示由进程P创建了进程Q.我们称进程P是进程Q的父进程,进程Q是进程P的子进程,这样便形成了进程树。
解:从上面的分析过程可以看出,执行第一个fork调用时,进程A创建了进程B;执 行第二个fork调用时,进程A创建了进程C,进程B创建了进程D:执行第三个fork调用 时,进程A创建了进程E,进程B创建了进程F,进程C创建了进程G,进程D创建了进程H。因此,在UNIX系统中运行题目中的程序,最多可产生7个进程,其进程家族树如图8.26所示。
四十二、(清华大学1996年试题)UNIX进程0的主要任务是什么? p252
解:当UNIX操作系统装入内存后,系统的控制权便由自举程序转到核心程序,即操 作系统程序上来。核心首先生成系统进程0,然后由0号进程创建一个1号进程(即init 进程),进程1负责初始化所有新的用户进程。实际上,1号进程是除了0号进程之外所有 用户进程的祖先。UNIX系统的调度与交换都是0进程的两部分,它们分别由swtch过程和 sched过程实现。sched过程把处于外存就绪态的进程换入内存,swtch则从就绪队列中寻找一优先级最高的进程。
因此,进程0的作用是:创建进程1,进行进程的调度和交换。 四十三、(清华大学1994年试题)请为下列程序中标号处加上注释。P253 程序A
#define MSGKEY 75 struct msgform{ longm type;
char mtext[256]; }
main() {
struct msgformmsg; int msgqid,pid,*pint;
msgqid=msgget(MSGKEY,0777); (1) pid=getpid();
pint=(int*)msg.mtext; (2) *pint=pid; (3) msg.mtype=1; (4)
msgsnd(msgqid,&msg,sizeof(int),O);(5) msgrcv(msgqid,&msg,256,pid,0); (6) )
程序B
#define MSGKEY 75 strct msgform{ longm type;
char mtext[256]; }msgl; main() {
int msgqid,i,pid,_pint;
msgqid=msgget(MSGKEY,0777|IPC_CREAT); msgrcv(msgqid,&msgl,256,1,0); (8) pint=(int*)msgl.mtext; (9) pid=*pint; (10) msgl.mtype=pid;
*pint=getpid(); (11)
(7) msgsnd(msgqid,&msgl,sizeof(int),O); (12) }
解:(1)获取一个消息队列标识,该消息队列的键值为MSGKEY,即75。消息队列
的权限为0777,即所有用户都有读、写、执行权限。 (2)使pint指向消息块中存放消息正文的空间。 (3)在消息正文中填入本进程的进程号。 (4)设置消息类型为1。
(5)发送消息。将上述两条语句构造好的消息发送至msgqid指定的消息队列。
(6)接收消息。在接收消息时,因消息类型设置为pid,即本进程的进程号,所以该
语句将读出消息类型为本进程进程号值的第一个消息。 (7)获取一个消息队列标识,该消息队列的键值为MSGKEY,即75。若给定键值尚
未有对应消息队列存在,就为它建立一个消息队列。消息队列的权限为0777。
(8)接收消息。在接收消息时,因消息类型设置为1,所以该语句将读出消息类型1 的第一个消息。
(9)使pint指向消息块中存放消息正文的空间。
(10)读出消息正文,放入变量pid中,即将程序A中所填入的进程号读出。
(11)在消息正文中填入本进程的进程号。 (12)发送消息。
四十四、假定盘块的大小为1KB,每个盘块号占4个字节,文件索引节点中的磁盘地址明
细表如图8.27所示,如何将下列文件的字节偏移量转换为物理地址? P256
(1)9000;(2)14000;(3)350000
[分析及相关知识] UNIX系统将文件的字节偏移量转换为文件物理块号的过程
分两步实现:第一步,将字节偏移量转换为文件逻辑块号及块内偏移量;第二步,
把逻辑块号转换为文件的物理块号.其转换方法如下: 首先,将字节偏移量转化为文件逻辑块号,即将字节偏移量除以盘块大小的字节
数,其商是文件逻辑块号,余数是块内位移量.
然后,把文件逻辑块号转换为物理盘块号.根据逻辑盘块号可知对应的文件地址
是直接地址还是间接地址,若为直接地址,即当文件逻辑盘块号小于10时,将文
件逻辑块号转换为索引节点的地址项下标,从该地址项中即可获得物理盘块号;
若为一次间接寻址,即当文件块号大于或等于10且小于266时,从索引节点的一
次间接项中得到一次间接的盘块号;再计算一次间接块中的地址下标,即将文件 的逻辑块号减10,从相应下标的地址项中得到物理块号;若为多次间接寻址,即
当文件的逻辑块号大于或等于266而小于65802时,应采用二次间接寻址,而当
逻辑块号大于或等于65802时,应采用三次间接寻址,多次间接寻址的转换方法
和一次间接寻址相类似,但要多次循环. 解:(1)字节偏移量为9000,此时 逻辑块号为:9000/1024=8
块内偏移量为:9000—8*1024=808
因逻辑块号小于10,因此该块为直接块。由图8.27可知,其物理盘块号为367,该块
中的第808字节即为文件的第9000字节。 (2)字节偏移量为14000,此时 逻辑块号为:14000/1024=13
块内偏移量为:14000—13*1024=688
因逻辑块号10<13<266,因此该块为一次间接块。 由图8.27可知,一次间接的盘块号为428,从一次间接块中读出盘块号表,查得其物
理盘块号为952,该块中的第688字节即为文件的第14000字节。
(3)字节偏移量为350000,此时 逻辑块号为:350000/1024=341
块内偏移量为:350000—341*1024=816
因逻辑块号266<341<65802,因此该块为二次间接块。
由图8.27可知,二次间接的盘块号为9156。由于一个一次间接块中可容纳266个块号, 341-266=75
因此字节偏移量350000在二次间接块的第0个一次间接块的第75个表项中,其盘块 号为333,该块中的第816字节即为文件的第350000字节。 四十五、编写一个程序,利用fork调用创建一个子进程,并让该子进程执行一个可执行文件。 解:本题要求利用fork创建一个子进程,并让子进程执行一个可执行文件,因此在实
现程序中,应先创建进程,再利用系统调用exec引入一个可执行文件。P259 main() {
int pid; pid=fork();
if(pid>O) /*父进程运行*/ {
wait((int*)0); /*等待子进程结束*/ pdntf(\"Is completed\\n\"); exit(0); }
if(pid==O) /*子进程运行*/ {
execl(“/bin/Is”,”ls”,”-l”,(char)0); /*引入并执行ls命令*/
fatal(“execl failed\"); /*fatal是一例行程序,可以完成简单的出错处理*/ }
fatal(”fork failed\"); /*执行到此处说明fork调用失败*/ } 四十六、试编写一个程序,说明命令这一层上的管道是怎样实现的。p262
[分析及相关知识] 在UNIX系统中,若干命令之间用“|”分隔,即组成一条管道线(不同于管道通信设施的一个概念),其功能是将前一个命令的输出作为下一个命令的输入。在该程序的实现中,利用了exec调用的一个特性,即已打开的文件经过exec调用后,仍保持打开;在引用exec之前,就把一个程序的标准输出连接到管道的写入端,把另一个程序的标准输入连接到管道的读出端。一般使用dup调用来完成这一工作,其调用方法如下: dup(fd);
如果调用成功,dup就返回一个新的文件描述符,新旧文件描述符通过同一个文件表项指向打开文件的索引节点,并且这个新的文件描述符是用户文件描述符表中当前最小编号的空表项。这一点非常重要,因为标准输入、标准输出和标准错误的文件描述符分别为0、1和2。 解:本题程序如下:
int join(com1,com2) /*用管道连接两个命令*/ char com1[],com2[]; {
int p[2],status;
switch(fork()) /*创建子进程*/ {
case -1: /*进程创建失败*/ fatal(“1st fork call failed”);
/*fatal是一例行程序,可以完成简单的出错处理*/
case 0: /*子进程执行*/ break;
default: /*父进程执行*/
wait(&status); /*等待子进程执行完*/ retum(status); }
/*后续程序由子进程执行,/ if(pipe(p)<0) /*创建管道*/ fatal(“pipe call failed\");
switch(fork()) /*创建另一个进程*/ {
case -1: 户进程创建失败*/ fatal(“2st fork call failed\"); case 0:
close(1); /*关闭标准输出*/
dup(p[1]); /*使标准输出指向管道写*/ close(p[0]); /*关闭管道读描述符*/ close(p[1]); /*关闭管道写描述符*/ execvp(com1[0],com1); /*引入命令1*/ fatal(“1st execvp failed\"): default:
close(0); /*关闭标准输入*/
dup(p[0]); /*使标准输入指向管道读*/ close(p[0]); /*关闭管道读*/ close(p[1]); /*关闭管道写,/
execvp(com2[0],com2): /*引入命令2*/ fatal(“2st execvp failed\"); } }
四十七、试述下面程序的运行结果。P264 #include int fdrd,fdwt; char c;main(argc,argv) int argc;
char *argv[]; {
if(argv!=3) exit(1);
if((fdrd=open(argv[l],O_RDONLY))==-1) exit(1);
if((fdwt=creat(argv[2],0666)==-1) exit(1); fork();
rdwrt(); exit(0); }
rdwrt() {
for(;;) {
if(read(fdrd,&c,1)!=1) return;
write(fdwt,&c,1); } }
[分析及相关知识] 在本题程序中,调用该程序应有两个参数,一个是已有的
文件名,另一个是要创建的新文件名.该程序打开已有的文件,创建一个新文件,
若上述两个系统调用成功,则再利用fork创建一个子进程。父进程和子进程在不
同的地址空间上运行相同的程序代码,每个进程都存取私有的全局变量fdrd,fdwt
和c及私有的栈变量argc和argv,但每个进程都不能存取另一进程的这些私有
变量.父进程和子进程分别独立地调用rdwrt函数,并执行函数中的循环,即从
源文件中读一个字节,然后写一个字节到目标文件中.当系统调用遇到文件尾时, 函数rdwrt立即返回。
由于在fork调用前,相应的文件已打开或创建,因此父进程和子进程通过相同的
文件表项共享对文件的存取,即两个进程的文件描述符fdrd都指向源文件的文件
表项,fdwt都指向目标文件的文件表项。这两个进程永远不会读或写到相同的文
件偏移量,因为核心在每次read和write调用之后,都要增加文件的偏移量。两
个进程合作完成了一次从源文件到目标文件的复制工作,每个进程完成了其中的
一部分文件复制任务,因此目标文件的内容依赖于核心调度两个进程的次序.如
果核心只在每个进程执行完一对read和write系统调用后才进行切换,即在每个
进程从源文件中读出的一个字节写入目标文件后才进行切换,则目标文件的内容
与源文件完全一致;否则,源文件的内容与目标文件不同。考虑下述情况,两个
进程正要读源文件中的两个连续的字符“ab”,假定父进程读了字符“a”,这时,
核心在父进程做写之前,进行上下文切换并调度子进程运行;如果子进程读到字
符“b”并在父进程被调度到之前将它写入目标文件,那么,目标文件将不再正确
地含有字符串“ab”,而是含有“ba”。
解:本程序完成的功能是将源文件复制到目标文件,父子进程合作完成此任务,但因 核心并不保证进程执行的先后顺序,源文件与目标文件字符个数及字符内容相同,但次序不一定相同,如源文件为“aba”,目标文件可能为“aab”。 四十八、试编写一个程序,打开已存在文件“test.txt”,将文件开始的几个字符改为“hi there\并在文件尾添加字符串“bye”。P268
[分析及相关知识] 为了将文件“test.txt”的开始几个字符改为“hlthere”, 用只写方式打开谊文件,然后写入字符序列“hi there”,接下来使用系统功能调用fcntl对打开文件的属性进行控制,使之以附加方式写丈件,再将字符串“bye”添加在文件尾。
系统调用fcntl提供对已打开文件的若干控制功能,其语法格式如下:
#include int fcntl(fd,cmd,arg); int fd,cmd,arg;其中,fd是已打开文件的文件描述符,系统调用fcntl将对fd所标识的文件起作用;cmd确定本次fcntl调用的功能;arg描述与cmd相关的参数.fcntl调用的功能较多,这里只说明与本题相关的两个功能,这两个功能由cmd值F_GETFL和F_SETFL确定。F_GETFL的功能是获取fd指定丈件的状态标志;F_SETFL的功能是设置fd指定文件的状态标志为arg。arg的可能取值为:0_NDELAY、0_APPEND和0_SYNC,分别表示以非等待方式读/写文件、以附加方式写文件及同步写.
解:
#include main() {int fd; fd=open(”test.txt\ /*以只写方式打开文件*/
write(fd,”hi there\\n”,9);
fcntl(fd,F_SETFL,O_WRONLY|O_APPEND); /*设置附加写标志*/
write(fd,”bye\\n”,4); close(fd); }
四十九、试说明下述程序的功能,并给出程序的运行结果(假设子进程的标识号为793)。P271 #include #include #include #include #include main() {int fd[2],cid_pid,status,len;
char buf[200]; if(pipe(fd)==-1) {
printf(“create pipe error\\n\"); exit(1); }
if((cld_pid=fork())=0) {
close(fd[1]);
1en=read(fd[0],buf,sizeof(buf)); buf[len]=0:
printf(“Child read pipe is--%s\n\ exit(0); } else {
close(fd[0]);
sprintf(buf,”Parent create this buf for cld%d\
write(fd[1],buf,strlen(buf)); exit(0); } }
[分析及相关知识] 该程序首先利用pipe系统功能调用创建一个管道,然后创 建一个子进程。父进程关闭管道读描述符(fd[0]),然后将一个字符串送入buf 中,再将buf中的信息写入管道;子进程关闭管道写描述符(fdll]),然后从管道中将数据读到buf中,再将buf中的信息显示在标准输出上。 解:本题程序的功能是创建一个管道,父进程通过管道向子进程发送一个字符串,子 进程将它显示出来。若子进程标识符为739,则其运行结果如下:
Child read pipe is--Parent create this buf for cld 793 五十、下面给出了两个程序,若以进程离开循环时的i值来标识进程,试画出这两个程
序产生的进程家族树。P272
程序A
#include #include #include main() {int i,pid:
for(i=1;i<4;i++) if(pid=fork()) break; }
程序B
#include #include #include main() {int i,pid;
for(i=1;i<4;++i)
if((pid=fork()<=0) break; }
[分析及相关知识] 在程序A中,fork每次执行时,返回给父进程的pid具有
非0值,因此将跳出循环;返回给子进程的pid为0值,因此成为下一轮循环中 的父进程。在程序B中,fork每次执行时,返回给父进程的pid具有非0值,因
此将继续循环;返回给子进程的pid为0值,因此将跳出循环。
解:程序A产生的进程家族树如图8.28所示,程序B产生的进程家族树如图8.29所示。
答