设备管理
P294页第5、7题。
5.
由柱面号可知调度顺序5,(1,2,3),4
由磁头号可知调度顺序5,3,(1,2),4
由扇区号可知调度顺序为5,3,2,1,4
综上所述 调度顺序为5,3,2,1,4 使磁盘旋转圈数最少
7.
先来先服务算法(FCFS):
(143-86)+(147-86)+(177-91)+(177-94)+(150-94)+(150-102)+(175-102)+(175-130)=565
最短查找时间有限算法(SSTF):
(147-143)+(150-147)+(150-130)+(130-102)+(102-94)+(94-91)+(91-86)+(175-86)+(177-175)=162
扫描算法:
(147-143)+(150-147)+(175-150)+(177-175)+(199-177)+(199-130)+(130-102)+(102-94)+(94-91)+(91-86)=169
电梯调度算法:
(147-143)+(150-147)+(175-150)+(177-175)+(177-130)+(130-102)+(102-94)+(94-91)+(91-86)=125
虚拟存储管理
P251,习题20
P252,习题31
分页存储管理和分段存储管理
1.采用相联存储器后地址转换过程,用图表示出来
2.详述分段管理和分页管理的区别。
3.P249 习题11。
解:
1、
2、
分段是信息的逻辑单位,由源程序的逻辑结构及含义所决定,是用户可见的,段长由用户根据需要来确定,段起始地址可从任何内存地址开始。在分段方式中,源程序(段号、段内位移)经链接装配后仍保持二维(地址)结构,引入目的是满足用户模式化程序设计的需要。
分页是信息的物理单位,与源程序的逻辑结构无关,是用户不可见的,页长由系统(硬件)确定,页面只能从页大小的整数倍地址开始。在分页方式中,源程序(页号、页内位移)经链接装配后变成一维(地址)结构,引入目的是实现离散分配并提高内存利用率。
3、
(1)649
(2)1727
(3)2301
(4)140
(5)1956
操作系统实验一:并发程序设计
一、实验目的
(1)加深对进程并发执行的理解,认识多进程并发执行的实质。
(2)观察进程共享资源的现象,学习解决进程互斥和同步的方法。
二、实验要求:
本实验要求用高级语言,启动多进程并发运行,设计相应代码,显示进程无关并发、进程共享变量并发的运行结果。并完成实验报告。
三、实验内容:
分别实现以下四种情况的并发:
1.并发的进程之间无关,显示进程名称,开始与结束时间。
模拟多终端售票情况,并发的多个终端进程之间共享剩余票数这个共享变量。
2.用全局变量实现。
3.用进程间共享数据机制实现。
4.用进程间共享数据机制和加锁机制实现。
四、实验过程与结果
- 算法思想与设计
- 算法实现代码
- 运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public class ThreadTest3 { public static void main(String[] args) { Shop shop = new Shop(); for ( int i = 1 ; i <= 5 ; i++) { new Thread(shop, "" ).start(); } } } class Shop implements Runnable{ String name; ticket t; public Shop() { t.total = 100 ; t.count = 0 ; } public void run() { while (t.total> 0 ) { synchronized ( this ) { try { Thread.sleep( new Random().nextInt( 1000 )); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "_____" +t.count); t.total--; t.count++; } } } } class ticket { int total; int count; } |
通过共享变量实现
import os import threading tickis=1000 lock=threading.Lock() def sale_tickis(thread_name): global tickis global lock while 1: lock.acquire() if tickis!=0: tickis-=1 print(thread_name,"余票为:",tickis) else: print(thread_name,"票卖完了") os._exit(0) lock.release() class my_thread(threading.Thread): def __init__(self,name=""): threading.Thread.__init__(self) self.name=name def run(self): sale_tickis(self.name) if __name__=="__main__": for i in range(1,21): thread = my_thread("线程" + str(i)) thread.start()
存储管理
1.试述计算机系统中的存储器层次。为什么要配置层次式的存储器?
计算机系统的存储器层次结构自上而下依次分为:寄存器、缓存、内存、磁盘、磁带5层
寄存器、缓存和内存属于操作系统存储管理的管辖范畴,磁盘和磁带属于文件管理和设备管理的管辖对象
配置层次式的存储器可以加快地址转换速度,提高程序执行速度。多层次的存储体系十分有效和可靠,能达到很高的性价比
2.简述不同编译、链接、装载与地址定位过程
编译:编译器将源程序转换成可重定位代码。其有三个逻辑地址块:代码段(机器指令块),数据段(静态变量块),栈段(表示程序执行时使用的栈)。
链接:链接程序的作用是根据目标模块之间的调用和依赖关系,将主调模块、被调模块以及所用到的库函数装配和链接成一个完整的可装载执行模块。根据程序链接发生的时刻和连接方式,程序链接可分成三种:静态链接,动态链接和运行时链接
装载:装载程序把可执行程序装入内存的方式有三种
(1)绝对装载:装在模块中的指令地址始终与其内存中的地址相同,即在模块中出现的所有地址都是内存绝对地址
(2)可重定位装载:根据内存当时使用情况,决定将装载代码模块放入内存的物理地址。模块内使用的地址都是相对地址
(3)动态运行装载:为提高内存利用率,装入内存的程序可换出到磁盘上,适当时候再换入到内存中,对换前后程序在内存中的位置可能不同,即允许进程的内存映像在不同时候处于不同位置,此时模块内使用的地址必为相对地址。
地址定位:可执行程序逻辑地址转换(绑定)为物理地址的过程称为地址重定位、地址映射或地址转换,可区分为三种地址重定位:静态地址重定位、动态地址重定位和运行时链接地址重定位。
3.什么是逻辑地址、物理地址?什么是静态地址重定位、动态地址重定位?
逻辑地址:指由程序产生的与段相关的偏移地址部分。有时我们也把逻辑地址称为虚拟地址
物理地址:物理内存,真实存在的插在主板内存槽上的内存条的容量的大小。内存是由若干个存储单元组成的,每个存储单元有一个编号,这种编号可唯一标识一个存储单元,称为内存地址(或物理地址)。我们可以把内存看成一个从0字节一直到内存最大容量逐字节编号的存储单元数组,即每个存储单元与内存地址的编号相对应。
静态地址重定位:由装载程序实现装载代码模块的加载和地址转换,把它装入分配给进程的内存指定区域,其中的所有逻辑地址修改成内存物理地址,称静态地址重定位
动态地址重定位:由装载程序实现装载代码模块的加载,把它装入分配给进程的内存指定区域,但对链接程序处理过的应用程序的逻辑地址则不做任何修改,程序内存起始地址被置入硬件专用寄存器——重定位寄存器。程序执行过程中,每当CPU引用内存地址时,由硬件截取此逻辑地址,并在它被发送到内存之前加上重定位寄存器的值,以便实现地址转换,称动态地址重定位
4.固定分区管理的缺点是什么?
(1)由于预先已规定分区大小,使得大作业无法装入,用户不得不采用覆盖等技术加以补救,这样不但加重用户负担,而且极不方便。
(2)内存空间利用率不高,作业很少会恰好填满分区。
(3)如果一个作业在运行过程中要求动态扩充内存空间,采用固定分区是相当困难的。
(4)分区数目是在系统初启时确定的,这就会限制多道运行程序的道数,特别不适应分时系统交互型用户及内存需求变化很大的形情。
5.简述固定分区存储管理和可变分区存储管理的区别
固定分区存储管理:分区大小是事先固定的,因而可容纳作业的大小受到限制,而且当用户作业的地址空间小于分区的存储空间时,造成存储空间浪费。
可变分区存储管理:不是预先将内存划分分区,而是在作业装入内存时建立分区,使分区的大小正好与作业要求的存储空间相等。这种处理方式使内存分配有较大的灵活性,也提高了内存利用率。但是随着对内存不断地分配、释放,操作会引起存储碎片的产生
6.某系统采用可变分区方式管理主存储器,在主存分配情况如图所示时,有4个作业要求装入主存,它们各自所需的主存空间为:J1:8KB,J2:15KB,J3:30KB,J4:115KB,系统不允许移动。用最先适应分配算法,按2341的作业顺序装入,描述作业装入内存的过程。
用信号量及其PV操作处理实际问题
43、现有3个生产者P1、P2、P3,他们都要生产橘子汁,每个生产者都已分别购得两种不同的原料,待购齐第三种原料后就可配制成橘子汁装瓶出售。有一供应商能源源不断的供应糖、水、橘子精,但每次只拿出一种原料放入容器中供应给生产者。当容器中有原料时,需要这种原料的生产者可以取走,当容器空时供应商又可放入一种原料。假定:生产者p1已购得糖和水;生产者P2已购得水和橘子精; 生产者P3已购得糖和橘子精; 试用: (1)管程(2)信号量和P、V操作写出供应商和3个生产者之间能正确同步的程序。
Cemaphore empty=1;
橘子精=0;糖=0;水=0;
Process product(){
While(true){
P(empty);
产生一个随机数s;
If(s==0) V(橘子精);
If(s==1) V(水);
If(s==2) V(糖);
}
}
Process P1(){
Process P2(){
Process P3(){
While(true){
while(true){
while(true){
P(橘子精);
P(糖);
P(水);
取走橘子精;
取走糖;
取走水;
V(empty);
V(empty);
V(empty);
}
}
}
}
}
}
Coend
2.IPO问题:有多个输入进程、多个处理进程和多个输出进程。输入进程把数据逐步输入到一个有M个单位缓冲区B1上,经处理进程处理之后放到有N个单位的缓冲区B2上,由输出进程进行输出。
a.这个问题有哪些进程?进程之间有什么样的制约关系?
b.用信号量及PV操作写出这些进程之间的同步算法
解:
a:有输入进程、处理进程、输出进程,进程之间有同步关系。
b: semaphore B1;B1=M; /*B1可用的空缓存区*/
semaphore B2;B2=N; /*B2可用的空缓存区*/
semaphore mutex;mutex=1; /*同步信号*/
cobegin
process input(){
while(true){
p(mutex);
输入;
B1--;
v(mutex);
}
}
process chuli(){
while(true){
p(mutex);
处理;
B1++;
B2--;
v(mutex);
}
}
process output(){
while(true){
p(mutex);
输出;
B2++;
v(mutex);
}
}
coend
用信号量进程同步与互斥
5
1、理解生产者和消费者问题
没有引入信号量时的生产者和消费者进程,什么情况下会出现结果不唯一?
什么情况下会出现永远等待?用信号解决生产者和消费者的同步与互斥,要求能自己写出来。
结果不唯一:假如当前的产品数为8,如果生产者生产一件产品投入缓存区,拟执行产品数加一操作;同时消费者取走一样产品,拟执行产品数减一操作;假如两者交替执行加一或减一操作,取决于其执行速度,产品数为9或7,但正确为8.
永远等待:假如消费者读取产品数为0时,调度程序暂停消费者进程,让生产者进程运行,生产者加入一个产品,将产品数加一,它便调用wakeup()函数来唤醒消费者;但是消费者未睡眠,则唤醒信号丢失,当消费者下次运行时,因已检测到产品数为0,于是去睡眠,当生产者将缓冲区填满后也去睡眠,这就会造成永远等待。
2、哲学家吃面问题
semaphore fork[5];
for(int i=0; i<5;i++)
fork[i]=1;
cobegin
process philosopher_i( ){
while(ture){
think( );
P(fork[i]);
P(fork[(i+10%5]);
eat();
V(fork[i]);
V(fork[(i+10%5]);
}
}
coend
3、读写文件问题
nt readcount=0;
semaphore writeblock=1,mutex=1;
cobegin
process reader_i() {
P(mutex);
readcount++;
if(readcount==1)
P(writerblock);
V(mutex);
/*读文件*/
P(mutex);
readcount--;
if(readcount==0)
V(writeblock);
V(mutex); }
coend
4、理发师问题
wait=0: //顾客信号量
barber=0://理发师信号量
custNum: //当前顾客数量
mutex=1: //互斥量
Barber(){
while(1){
P(wait); //唤醒等待的一位顾客
P(mutex); //顾客被唤醒,准备理发,没有顾客,则睡觉
custNum--; //当前店里顾客数减1
V(barber); //有顾客来了,醒来理发
V(mettux): //释放互斥信号量
}
}
Customer(){
while(1){
P(mutex); //顾客想要理发
if(custNum<N){ //店里人没有满
custNum++;
V(wait); //理发师睡觉的话,唤醒他理发
V(mutex); //释放互斥量,理发这一动作成功
P(baber); //理发师进行理发操作
}
else
{
V(metux); //释放互斥量,打消进店理发的举动
}
}
}
5、在一间酒吧里有三个音乐爱好者队列,第一队的音乐爱好者只有随身听,第二队只有音乐磁带,第三队只有电池。而要听音乐就必须随身听、音乐磁带和电池这三种物品俱全。酒吧老板一次出售这三种物品中的任意两种。当一名音乐爱好者得到这三种物品并听完一首乐曲后,酒吧老板才能再一次出售这三种物品中的任意两种。于是第二名音乐爱好者得到这三种物品,并开始听乐曲。全部买卖就这样进行下去。试用P,v操作正确解决这一买卖。
semaphore muext=1;
cobegin
process boss(){
P(muext);
/*老板任意出售两种*/
V(muext);
}
process musiclovers_i() {
while(ture){
P(muext);
listening();
V(muext);
}
coend
6、某银行有人民币储蓄业务,由n个储蓄员负责。每个顾客进入银行后先取一个号,并且等着叫号。当一个储蓄人员空闲下来,就叫下一个号。请用P,V操作正确编写储蓄人员和顾客进程的程序。
Var mutex=1,customer_count=0:semaphore;
Cobegin
process customer
begin
repeat
P(mutex);
取号码,进入队列;
V(mutex);
V(customer_count);
untile false;
end
process serversi(i=1...n)
begin
repeat
P(customer_count);
P(mutex);
从队列中取下一个号码;
V(mutex);
为该号码持有者服务;
untile false;
end
Coend
7、面是两个并发执行的进程。它们能正确运行吗?若不能请举例说明,并改正之。(5分)
parbegin
var X:integer;
process P1 process P2
var y,z:integer: var t,u:integer;
begin begin
x:=1; x:=0:
y:=0: t=0;
if x≥l then y:=y十1; if x≤l then t:=t+2;
z:=y; u:=t;
end; end;
parend.
parbegin
var x:integer; var s:semaphore:=1;
process P1 process P2
var y,z:integer ; var ,t,u:integer ;
begin begin
P(s); P(s);
x:=1; x:=0;
y:=0; t:=0;
if x>=1 then y:=y+1; if x<=1 then t:=t+2
V(s); V(s);
z:=y; u:=t;
end end
parend
8、在一个盒子里,混装了相等数量的黑棋子和白棋子,现要用自动分拣系统把黑棋子和白棋子分开,该系统由两个并发执行的进程P1和P2组成,其中进程P1专门拣黑子,进程P2专门拣白子。规定两个进程轮流拣子且每个进程每次只拣一个子。当一个进程在拣子时不允许另一个进程去拣子,并设P1先拣。请用P,V操作管理这两个并发进程,使其能正确实现上述功能。
var s1,s2:semaphore;
s1:=1;
s2:=0;
cobegin
Process p1
begin
repeat
P(s1);
拣黑子;
V(S2);
untile false;
end
process p2
begin
repeat
P(s2);
拣白子;
V(s1);
untile false;
end
coend