操作系统期末总结文档和考试卷解析

任课老师为黑龙江大学金虎


实验的源代码较多,但是由于未完整实现一个功能,也不好上传到github上,我就直接上传到百度云盘了,可能之后有一些黑大的学生搜索参考的时候要用到。


百度云盘地址:http://pan.baidu.com/s/1jGoxW0Y


贴一下读书报告和实验总结报告吧,这样版面也不会太空,贴出来的2份报告只有文字没有图,所以可能理解会有一些问题,真有需要的同学请下载云盘里的文件。

说实话读书报告这个东西有点虚,我并没有实际的跟着《自己动手写操作系统》这本书去真正写一个操作系统,只是了解了其中的一些知识。

 

 “操作系统课程设计”读书报告


黑龙江大学计算机科学技术学院 软件学院
 
一、基本理论阐述
理论要结合实际
——如何真正写一个操作系统
虽说万事开头难.但有时也未必。比如说,写一个有实用价值的操作系统是一项艰巨的工作。但一个小的操作系统或许很容易实现了。现在我们就来实现一个小得无法再小的“操作系统”。建议你跟随书中的介绍一起动手来做。你会发现不但很容易,而且很有趣。
1.1	准备工作
我们需要准备:
1.	硬件
一台计算机(windows操作系统)
一张空白软盘
2.	软件
汇编编译器 NASM
软盘绝对扇区读写工具,比如FlooppyWriter.exe

注意:这个方法显然已经不能再现在使用了,现在的我甚至找不到一张软盘。所以这个结合实际是指了解一个底层的能直接运行的操作系统应该是怎么诞生的。
1.2 10分钟完成的操作系统
	你相不相信,一个“操作系统”可以只有20行代码?请看:
	ORG 07C00H		;告诉编译器程序加载到了7C00处
	MOV AX,CS
	MOV DS,AX
	MOV ES,AX
	CALL DISPSTR		;调用显示字符串例程
	JMP $			;无限循环
DISPSTR:
	MOV AX,BOOTMESSAGE
	MOV BP,AX		;ES:BP = 长度
	MOV CX,16		;CX = 串长度
	MOV AX,01301H	;AH = 13,AL = 01H
	MOV BX,000CH		;页号为0(BH = 0)黑底红字(BL = 0CH,高亮)
	MOV DL,0
	INT 10H			;10H号中断
	RET
BOOTMESSAGE:		DB	“HUORAN,I LOVE U --HELLOCLYDE”
TIMES	510-($-$$)	DB	0	;填充剩下的空间,使生成的二进制代码
;恰好为512字节
DW		0XAA55				;结束标志


把这段代码用NASM编译一下:
NASM BOOT.ASM –O BOOT.BIN
我们就得到了一个512B的boot.bin,使用软盘绝对扇区读写工具将这个文件写到一张空白软盘的第一个扇区。好了,你的第一个“操作系统”就已经完成了。这张软盘已经是一张引导盘了。
把它放到软驱中重新启动计算机,从软盘引导,就能看到操作系统的模样了。

1.2	Boot Sector
实际上,你刚刚所完成的并不是一个完整的OS,而仅仅是一个最最简单的引导扇区(Boot Sector),然而不管我们完成的是什么,至少,它是直接在裸机上运行的,不依赖于任何其他软件,所以,这和我们平时所编写的应用软件有本质的区别。它不是操作系统,但是已经具备了操作系统的一个特性。
	当计算机电源被打开时,它会先进行加电自检(POST),然后寻找启动盘,如果是选择从软盘启动,计算机就会检查软盘的0面0磁道1扇区,如果发现它以0xAA55(假如我们把此扇区看作一个字符数组sector[]的话,那么此结束标志相当于sector[510] = 0x55,且sector[511]=0xAA)结束,则BIOS认为它是一个引导扇区,也就是我们说的Boot Sector。当然,一个正确的Boot Sector除了以0xAA55结束之外,还应该包含一段少于512B的执行码。
	好了,一旦BIOS发现了Boot Sector,就会将这512B的内容装载到内存的0000:7c00处,然后跳转到0000:7c00处将控制权彻底交给这段引导代码。到此为止,计算机不再由BIOS中的固有的程序来控制,而变成由操作系统的一部分来控制。
	现在,你可能明白了为什么在那段代码的第一行会出现org 07c00这样的代码,没错,这行代码就是告诉编译器,将来我们的这段程序要被加载到内存偏移地址7c00处。
1.3	代码解释
其实程序的主体框架只有5行(从第2行到第6行),其中调用了一个显示字符串的子程序。程序的第2、3、4行是3个mov指令,使ds和es两个段寄存器指向与cs相同的段,以便在以后进行数据操作的时候能定位到正确的位置,第5行调用子程序显示字符串,然后jmp $让程序无限循环下去。
	可能大部分人开始学汇编时用的都是MASM,其实NASM的格式跟MASM总体上是差不多的。
	我们学校练习汇编就是使用MASM。
在这段程序中,值得说明的地方有以下几点:
1.	在NASM中,任何不被方括号[]括起来的标签或者变量名都被认为是地址,访问标签中的内容必须使用[],所以,
mov ax,BootMessage
		将会把“HuoRan,I love U --HelloClyde”这个字符串的首地址传给寄存器ax。又比如,如果有:
			FOO DW 1
		则mov ax,foo 将把foo的地址传给ax,而mov bx,[foo]将把bx的值赋为1。
			实际上,在NASM中,变量和标签是一样的,也就是说:
			FOO DW 1 = FOO : DW 1
			而且你会发现,Offset这个关键字在NASM也是不需要的。因为不加方括号时表示的就是Offset。
			笔者认为这是NASM的一大优势,要地址就不方括号,也不必额外地用什么Offset,想要访问地址中的内容就必须加上方括号。代码规则非常鲜明,一目了然。
2.	关于$和$$,$表示当前行被汇编后的地址。这好像不太好理解,不要紧,我们把刚刚生成的二进制代码文件反汇编来看看:
NDISAAMW –O 0X7C00 BOOT.BIN >> DISBOOT.ASM
打开disboot.asm,你会发现这样一行:
00007C09	EBFE	JMP SHORT 0X7C09
其实我觉得这很好理解,根本不用举例,让我打了这么多字,一个没看过汇编和编译原理的人怎么会来看操作系统的相关书。
那么$$表示什么呢?它表示一个节的开始处被汇编后的地址。实例程序已有一个节,所以$$就表示程序开头0x7c00。
这里的section属于NASM规范的一部分,表示一段代码,关于它和$$更详细的注释请参考NASM联机技术文档。
在写程序的过程中,$-$$可能会被经常用到,它表示本行距离程序开始处的相对距离。现在,你应该明白510-($-$$)表示什么意思了吧?times 510-($-$$) db 0表示将0这个字节重复510-($-$$)遍,就是在剩下的空间中不停地填充0,知道程序有510B为止。
这样,加上结束标志0xAA55占用的2B,恰好就是512B。
1.4	水面下的冰山
即便是非常袖珍的程序,也有可能遇到不能正确运行的情况,对此你一定并不惊讶,谁都可能少写一个标点,或者在一个小小的逻辑问题上犯迷糊。好在我们可以调试,通过调试,可以发现错误,让程序日趋完美。但是对于操作系统这样的特殊程序,我们没有办法用普通的调试工具来调试。可是,哪怕一个小小的Boot Sector,我们也没有十足的把握一次就写好,那么遇到不能正确运行的时候该怎么办呢?在屏幕上没有看到我们所要的东西,甚至于机器一下子重启了,你该如何是好呢?
	每一个问题都是一把锁,你要相信,世界上一定存在一把钥匙可以打开这把锁。你也一定能找到这把钥匙。
	一个引导扇区代码可能只有20行,如果Copy&Paste的话,10秒钟就搞定了,即使自己敲键盘抄一遍下来,也用不了10分钟。
	复制粘贴的话,哪怕一万行的代码也不用10秒钟。
	可是,在遇到一个问题时,如果不小心犯了小错,自己到运行时才发现,你可能不得不花费10个10分钟设置更长的时间来解决它。笔者把这20行的程序称作水面以上的冰山,而把你花了数小时的时间做的工作称作水面下的冰山。
	这点,深有体会。作为一个程序员有2大难题,一个是解决思路,一个就是调试问题。特别是当调试工具不够完善的时候,往往要花费大量的时间去调试,面对特殊的数据结构或者资源,往往还要自己写工具去帮助调试。
		古人云:“授之以渔不如授之以渔。”下面都是笔者经历了一些痛苦的摸索之后的一些心得,这些方法可能不是最好的,但至少可以给你提供一个参考。
		好了,以Boot Sector为例,你可以想象的到,将来我们一定会对这20行进行扩充,最后得到200行甚至更多的代码,我们总得想一个办法,让它调试起来容易一些。其实很容易,我们只要把“org 07c00h”这一行改成“org 0100h”就可以编译成一个.com文件让它在DOS下运行了。我们来试一试,首先把07c00h改成0100h,编译:
		NASM BOOT.ASM –O BOOT.COM
		好了,一个易于执行和调试的Boot Sector就制作完毕了。调试.com文件可能让你仿佛一下子回到了20世纪,没关系,怀旧一下感觉还是蛮不错的。
		Turbo Debugger是一个不错的调试工具,“图形化”界面,全屏操作,用起来感觉和一个“严重”精简后的windows差不多。
		调试完之后要放到软盘上进行试验,我们需要再把0100h该成07c00h,这样改来改去比较麻烦,好在强大的NASM给我们提供了预编译宏,把原来的“org 07c00h”一行变成许多行即可:
		;%DEFINE	_BOOT_BEBUG_
		%IFDEF	_BOOT_DEBUG_
			ORG 0100H
		%ELSE
			ORG 07C00H
		%ENDIF
	这样一来,如果我们想要调试,就让第一行有效,想要做Boot Sector时,将它注释掉就可以了。
	这个调试方式也用于现在的很多工程,对于在运行过程中要输出中间内容用于排错等问题的解决很有用。但是我编程习惯一般,我一般都是手动注释掉,之后要修改排错就比较麻烦。

3.1 认识保护模式
	很多时候,我觉得自己是懒惰和急功近利的,在学习新东西的时候不肯花时间阅读大段概念性的叙述,我认为那是给已经明白了的人看的,当我也懂了的时候,我可能能弄清楚作者在说些什么,可当我初学的时候,我真的不太喜欢泛泛的介绍,我想尽快看到些吸引眼球的东西。
	但是我觉得还是直接看概念的好。所以我跳过了这段长代码。
	;=====================
	;PMTEST1.ASM
	;编译方法:NASM PMTEST1.ASM –O PMTEST1.COM
	;=====================
	%INCLUDE	“PM.INC”	;常量、宏,以及一些说明
	ORG 0100H
		JMP LABEL_BEGIN
	[SECTION .GDT]
	;GDT
	LABEL_GDT:	DESCRIPTOR	0,0,0	;空描述符
	LABEL_DESC_CODE32:	DESCRIPTOR	0,SEGCODE32LEN – 1,DA_C + DA_32
										;代码段,32位
	LABEL_DESC_VIDEO:	DESCRIPTOR	0B8000H,0FFFFH,DA_DRW
										;显存首地址
	;GDT结束
	GDTLEN	EQU	$	-LABEL_GDT	;GDT长度
	GDTPTR	DW	GDTLEN				;GDT界限
			DD	0					;GDT基地址
	;GDT选择子
	SELECTORCODE32	EQU	LABEL_DESC_CODE32	-	LABEL_GDT
	SELECTORVIDEO		EQU	LABEL_DESC_VIDEO		-	LABEL_GDT
	;END OF [SECTION .GDT]
	[SECTION	.S16]
	[BITS	16]
	LABEL_BEGIN:
		MOV	AX,CS
		MOV DS,AX
		MOV ES,AX
		MOV SS,AX
		MOV SP,0100H
		;初始化32位代码段描述符
		XOR EAX,EAX
		MOV AX,CS
		SHL EAX,4
		ADD EAX,LABEL_SEG_CODE32
		MOV WORD [LABEL_DESC_CODE32 + 2],AX
		SHR EAX,16
		MOV BYTE [LABEL_DESC_CODE32 + 4],AL
		MOV BYTE [LABEL_DESC_CODE32 + 7],AH
		;为加载GDTR做准备
		XOR EAX,EAX
		MOV AX,DS
		SHL EAX,4
		ADD EAX,LABEL_GDT				;EAX <- GDT 基地址
		MOV DWORD [GDTPTR + 2],EAX			;[GDTPTR + 2] <- GDT 基地址
		
		;加载GDTR
		LGDT [GDTPTR]
		
		;关中断
		CLI
		;代开地址线A20
		IN AL,92H
		OR AL,00000010B
		OUT 92H,AL
		;准备切换到保护模式
		MOV EAX,CR0
		OR EAX,1
		MOV CR0,EAX
		;真正进入保护模式
		JMP DWORD SELECTORCODE32:0		;执行这一句会把SELECTORCODE32
									;装入CS,并跳转到
									;SELECTORCODE32:0处
	[SECTION .S32];32位代码段,由实模式跳入
	[BITS 32]
	LABEL_SEG_CODE32:
		MOV AX,SELECTORVIDEO
		MOV GS,AX			;视频段选择子(目的)
		MOV EDI,(80 * 10 + 0) * 2;屏幕第10行,第0列
		MOV AH,0CH			;0000:黑底	1100:红字
		MOV AL,’P’
		MOV [GS:EDI],AX

		;到此停止
		JMP $
	SEGCODE32LEN EQU $ -LABEL_SEG_CODE32
	;END OF [SECTION .S32]
这段代码将实现由实模式到保护模式的转换。至于实模式和保护模式的概念及区别,我们之后再做详细解释,现在,先让我们把这段过一遍,分别看一下它的三个部分。
	你可能注意到了,在最开头处的注释中,这个程序被编译成了.COM文件,最简单的二进制文件。这意味着程序执行时的内存映像和二进制文件的映像是一样的。所以,在上面的程序中定义的section并没有什么实质上的作用,即便不定义它们,从执行结果来看也是一样的(编译出来的二进制会有微小差别)。定义它们只是使代码结构上比较清晰,而且,后面我们对这个程序渐渐扩展的时候,它还有一点小小的作用。
	好了,首先说说[SECTION.gdt]这个段,其中的Descriptor是在pm.inc中定义的宏:
	;描述符
	;USAGE: DESCIPTOR BASE,LIMIT,ATTR
	;	BASE: DD
	;	LIMIT: DD (LOW 20 BITS AVAILABLE)
	;	ATTR: DW (LOWER 4 BITS OF HIGHER BYTE ARE ALWAYS 0)
	%MACRO DESCRIPTOR 3
		DW %2 & 0FFFFH		;段界限1	(2字节)
		DW %1 & 0FFFFH		;段基址1	(2字节)
		DB (%1 >> 16) & 0FFH	;段基址2	(1字节)
		DW ((%2 >> 8) & 0F00H) | (%3 & 0F0FFH)
								;属性1 + 段界限2 + 属性2(2字节)
		DB (%1 >> 24) & 0FFH			;段基址 3	(1字节)
%ENDMACRO	;共8字节
	先不要管具体的意义是什么,看字面我们可以知道,这个宏表示的不是一段代码,而是一个数据结构,它的大小是8字节。
	在段[SECTION.GDT]中并列有3个Descriptor,看上去是个结构数组,你一定猜到了,这个数组的名字叫做GDT。
	GdtLen是GDT的长度,GdtPtr也是个小小的数据结构,它有6字节,前2字节是GDT的长度,后4字节是GDT的基地址。
	另外还定义了两个形如SelectorXXXX的常量,至于是做什么用的,我们暂且不管它。
	在往下到了一个代码段,[BITS 16]明确地指明了它是一个16位代码段。你会发现,这段程序修改了一些GDT中的值,然后执行了一些不常见的指令,最后通过jmp指令实现一个跳转:
	JMP SELECTORCODE32:0
	正如代码注释中所说的,这一句将“真正进入保护模式”。实际上,它将跳转到第三个section,即[SECTION .S32]中,这个段是32位的,执行最后一小段代码,这段代码看上去是往某个地址处写入了2字节,然后就进入了无限循环。
	虽然我们还没有能够了解更多细节,但是我猜,你一定在想这段程序的执行结果回事怎么样的,我们先来看一下。
	首先然找注释中所说的方法编译:
	NASM PMTEST1.ASM –O PMTEST1.COM
	然后在VirtualPC中运行它。
	VirtualPC是虚拟机,因为书上的内容都有点老,所以都需要用虚拟机去模拟出一个环境。

	可以看到,程序打印了一个红色的字符P,然后再也不动了。不难猜到,程序的最后一部分代码中写入的2字节是写入了显存中。
	现在,大致的感性认识已经有了,但你一定有一些疑惑,什么是GDT?那些看上去怪怪的指令到底在做什么?现在我们先来总结一下,在这个程序中,我们了解到什么,有哪些疑问。
	我们了解到的内容如下:
1.	程序定义了一个叫做GDT的数据结构
2.	后面的16位代码进行了一些与GDT有关的操作。
3.	程序最后跳到32位代码中做了一点操作显存的工作
我们不明就里内容如下:
1.	GDT是什么?它是干什么用的?
2.	程序对GDT做了什么?
3.	那个jmp SelectorCode32:0跟我们从前用过的jmp有什么不同?
好了,下面我们将一一解答这些问题,并以此为突破口引领你走进保护模式的大门。在解答过程中,我想说明的是,本章不打算成为全面介绍保护模式的课程,本着够用的原则,我们不会涉及保护模式的所有内容,只要能自由地编写操作系统代码就足够了。一个典型的例子是V86,它是保护模式的一部分,但是如果你不想在自己的操作系统中支持16位程序,你可能永远都不需要知道它的实现方法,学习它简直是对自己宝贵时间的浪费。还有一点就是,通过由一个简单程序辐射开来的方式学习一个并不简单的体系,开始对某些地方的认识可能是片面的,这没有关系,随着我们对这个程序的不断扩充,你终究会有比较全面的了解。
	好的,现在就让我们出发,跟我一起走进保护模式。
3.1.1 GDT(Global Descriptor Table)
	在IA32下,CPU有两种工作模式,实模式和保护模式。直观的看,当我们打开自己的PC,开始时CPU是工作在实模式下的,经过某种机制后,才进入保护模式。在保护模式下,CPU有着巨大的寻址能力,并为强大的32位操作系统提供了更好的硬件保障。如果你还是不明白,我们不妨这样类比,实模式到保护模式的转换类似于政权的更替,开机时实在实模式下,就好像皇帝A在执政,他有他的一套政策,你需要遵从他订立的规则,否则有可能被杀头。后来通过一种转换,类似于革命,新皇帝B登基,登基的那一刻类似于程序中那个历史性的jmp。之后,B又有他的一套完全不同的新政策。当然,新政策比老政策好很多,对人民来说有更广阔的自由度,虽然它要复杂的多,这套新政策就是保护模式。我们要学习的,就是新政策是什么,我们在新政策下应该如何做事。
	
二、当前应用现状
操作系统是靠近硬件的软件层,其功能是直接控制和管理系统资源(包括软件、硬件)。计算机系统的硬件在操作系统的管理和控制下,其功能得以充分发挥。从用户观点看,引入操作系统后,计算机系统成为一台硬件系统功能更强、服务质量更高、使用更方便的机器。操作系统与其他系统软件一起向用户提供了一个良好的工作环境,用户无需了解许多与硬件和系统软件的细节,就能方便的使用计算机。
操作系统在硬件系统上运行,它常驻内存内,并提供给上层两种接口:操作接口和编程接口。操作接口由一系列操作命令组成,用户通过操作接口可以方便地使用计算机。编程接口由一系列的系统调用组成各种程序可以使用这些系统调用让操作系统为其服务,并通过操作系统来使用硬件和软件资源。所以其他程序是在操作系统提供的功能基础上运行的。
操作系统的作用主要体现在两方面:
1.屏蔽硬件物理特性和操作细节,为用户使用计算机提供了便利的指令系统(成千上万条机器指令,它们的执行由微程序的指令解释系统实现的)。计算机问世初期,计算机工作者就是在裸机上通过手工操作方式进行工作。
2.有效管理系统资源,提高系统资源使用效率,如何有效地管理、合理地分配系统资源,提高系统资源的使用效率是操作系统必须发挥的主要作用。
而到了现在,操作系统更是计算机行业里不可分割的一部分。
现代操作系统通常都有一个使用的绘图设备的图形用户界面(GUI),并附加如鼠标或触控面版等有别于键盘的输入设备。旧的OS或性能导向的服务器通常不会有如此亲切的界面,而是以命令行界面(CLI)加上键盘为输入设备。以上两种界面其实都是所谓的壳,其功能为接受并处理用户的指令(例如按下一按钮,或在命令提示列上键入指令)。
选择要安装的操作系统通常与其硬件架构有很大关系,只有Linux与BSD几乎可在所有硬件架构上运行,而Windows NT仅移植到了DEC Alpha与MIPS Magnum。在1990年代早期,个人计算机的选择就已被局限在Windows家族、类Unix家族以及Linux上,而以Linux及Mac OS X为最主要的另类选择,直至今日。
大型机与嵌入式系统使用很多样化的操作系统。在服务器方面Linux、UNIX和WindowsServer占据了市场的大部分份额。在超级计算机方面,Linux取代Unix成为了第一大操作系统,截止2012年6月,世界超级计算机500强排名中基于Linux的超级计算机占据了462个席位,比率高达92%。随着智能手机的发展,Android和iOS已经成为目前最流行的两大手机操作系统。 
2012年,全球智能手机操作系统市场份额的变化情况相对稳定。智能手机操作系统市场一直被几个手机制造商巨头所控制,而安卓的垄断地位主要得益于三星智能手机在世界范围内所取得的巨大成功。2012年第三季度,安卓的市场份额高达74.8%,2011年则为57.4%。2013年第一季度,它的市场份额继续增加,达到75%。虽然 Android 占据领先,但是苹果 iOS 用户在应用上花费的时间则比 Android 的长。虽然在这方面 Android 的数字一度接近苹果,但是像 iPad 3 这样的设备发布之后,苹果的数字还是会进一步增长。Windows Phone 系统在 8.1 版发布后市场份额稳步提高,应用生态正在改善,众多必需应用不断更新,但是速度还略嫌迟缓。微软收购了诺基亚,发展了许多OEM厂商,并不断发布新机型试图扭转WP的不利局面,小有成效。

三、对真正写一个操作系统的体会
真正写一个操作系统,不仅仅需要扎实的操作系统原理支持,而且需要很强的专研精神,和很强的动手能力。
操作系统原理这门课不同于编译原理,学习了编译原理以后马上就可以写出一个小型的编译器,然而操作系统却不行。一个是平台搭建难,在《自己动手写操作系统》一书中,有整整一章描述如何搭建编译平台,可能在以后的编程生活中,这只不过是个平常小事,然而对于刚刚接触的大学生来说,平台的搭建就是一头拦路虎。
第二个,编写操作系统需要极强的细节掌控能力和调试能力。就如同书里说的,编写操作系统程序不同于其他程序,由于是底层的软件,调试很难,一个错误可能就会发生连环的错误,让我们无从下手。
还有就是操作系统需要一定的汇编知识,汇编不同于一些高级语言,由于汇编指令繁多,规则多,所以编写汇编程序甚至需要一边拿着手册一遍写。虽然《自己动手写操作系统》一书中有关于C语言和汇编联合编写的内容,但是没有强大的汇编基础是肯定不行的。

四、课程设计过程中的应用与实践
在阅读《自己动手写操作系统》一书中,我尝试了使用了VmWare虚拟机来实现第一章20行代码的运行。书里提供的好多工具都已经不能再windows8.1上运行了,我先装了一个windows XP的虚拟机才能运行这些工具。然而我也没有找到这些工具的替代版本,或许,现在的操作系统已经不是这么写了也说不定。
计算机科学技术发展很快,所以与时俱进也是一个程序员应该有的特性。
看了书后也理解了计算机引导的原理。也明白了操作系统离我们并没有那么远,我们自己也可以写。也通过事实证明操作系统只是一个资源管理者,而不是解释执行工具,并不会对性能造成很大的影响。同时也发现操作系统容易被黑客入侵的可能,只要代码是直接注入内存运行的,那么哪怕操作系统的检查再严厉,代码还是有可能绕过操作系统对计算机进行管理。

五、读书工程心得总结
读书工程可以说是强制让我们读书。对于我个人来说读的书还是比较少的,因为如果遇到什么问题,我一般都会去网上寻找解决方案。但是获得的解决方法虽然解决了问题,但是知其然不知其所以然。读书工程给了一次机会,让我能系统的学习关于操作系统的相关知识。有时候静下来完整的读一本书真的对于专业学习很有帮助。

参考文献
1.	操作系统-百度百科词条 2015-06-27
2.	自己动手写操作系统/于渊编著.-北京:电子工业 出版社,2005.8

 

“操作系统课程设计”总结报告


黑龙江大学计算机科学技术学院 软件学院
本学期开设了操作系统课程,为了更好的理解操作系统理论,掌握其应用,特设此操作系统实验课程,在该操作系统实验中包括进程管理、存储管理、设备管理和文件管理等五个部分。
一、	进程控制
1.1目的
利用简单的结构和控制方法模拟进程结构、进程状态和进程控制。
1.2内容
1、	用PCB表示整个进程实体,利用随机数方法或键盘控制方法模拟进程执行中产生的事件,或者利用基于图形界面的鼠标或者键盘操作控制进程管理内容。
2、	定义PCB:包括理论PCB中的基本内容,如内部ID、外部ID、队列指针。由于很难实现真正的进程创建功能,在实验中只需建立PCB节点,并用它代表一个完整的进程。每创建一个进程时,可动态分配PCB节点,对相应内容赋值,并链接到适当的队列上。
3、	定义进程状态转换方式:真实的进程状态转换是由进程内部操作或操作系统的控制引起的。由于模拟程序中无法实现这些功能,我们可以采用随机数方法或键盘控制方法模拟,并实现对应的控制程序。随机方法指产生1-5的随机数,分别代表创建进程(1)、时间片到(2)、进程阻塞(3)、唤醒进程(4)、结束进程(5)等事件;键盘模拟方法指定义5个选项菜单代表以上五种事件。
4、	根据随机数或键盘操作处理就绪队列、阻塞队列和当前执行进程的状态。每次事件处理后应显示出当前系统中的执行进程是哪一个,就绪队列和阻塞队列分别包含哪些进程。
5、	*(带*部分为试验班和特长班需要完成的内容,普通班选作)完成可变分区的分配与回收,创建进程的同时申请一块连续的内存空间,结束进程同时回收分配的内存空间。分配采用最佳适应算法,碎片大小为2Kb,最后回收所有进程的空间。可以查看进程所占的空间和系统空闲空间。
实验结果:
 
1.3数据结构
 
1.4算法设计及流程图
CreateProcess:
 
ExecuteProcess:
 
BlockProcess:
 
TimeOver:
 
DestoryProcess:
 
二、请求分页存储器管理
2.1目的
在第1部分实验基础上实现进程的分页式内存分配和地址转换过程,并进一步实现请求分页式存储分配和地址转换过程。页面置换算法至少应实现先进先出(FIFO)、最近最久未使用(LRU)等算法。

2.2内容
1、	建立1个位示图,用来模拟内存的分配情况,位示图的位数与设定的物理块个数相同。
2、	创建进程时输入进程大小,并根据程序中设定的物理块大小为进程分配物理块,同时建立页表。
3、	输入当前执行进程所要访问的逻辑地址,并将其转换成相应的物理地址。
4、	进程退出时,根据其页表内容向位示图反向回填“0”。
5、	扩充页表,将其变成支持请求和置换功能的二维页表(增加存在位等)。创建进程时可装入固定的前三页(或键盘输入初始装入页数,不同进程的装入个数可以不同),其余页装入到置换空间内(置换空间大小应为内存空间大小的1.5-2倍,对其还需建立独立的置换空间位示图)。
6、	分别采用FIFO或LRU置换算法对地址转换过程中遇到的缺页现象进行页面置换,可将多次地址转换过程中所涉及到的页号视为进程的页面访问序列,从而计算置换次数和缺页率。
实验结果:
 
2.3数据结构
 
2.4算法设计及流程图 
AddressTransformate:
 

2.5小结
操作系统请求分页储存器我写的不够好,特别是多个调度算法之间的切换,并没有一个统一的接口,导致代码混乱,修改麻烦。


三、设备管理
3.1目的
在前面的实验基础上实现设备管理功能的模拟,主要包括通道和控制器的添加和删除,设备的添加、删除,设备的分配和回收。
3.2内容
1、	假定模拟系统中已有键盘、鼠标、打印机和显示器四个设备,另有三个控制器和两个通道。
2、	设备管理子系统涉及到系统设备表(SDT)、通道控制表(CHCT)、控制器控制表(COCT)和设备控制表(DCT)来体现输入输出系统的四级结构和三级控制。应实现上述数据结构来完成对外围设备的管理。
3、	实现上述设备、控制器以及通道的层次关系,同时能够添加或删除新的设备、控制器或通道。
4、	通过键盘命令模拟进程执行过程中提出的设备分配或释放请求,并为此请求分配或释放设备。分配设备成功后可将进程状态调整为阻塞,释放设备后变为就绪状态。
5、	分配设备时应如果该设备已被其它进程占用,则设备分配失败,请求进程进入阻塞状态,同时等待该设备的释放。如果设备空闲,进程占用设备的同时还应提出申请控制器请求,直到与设备相关的通道都已申请成功为止。
6、	设备、控制器或通道的释放应引起对应节点的等待队列中的第一个阻塞进程被唤醒。如果被唤醒的进程还未完成申请操作,应继续执行上级节点的申请操作。
   实验结果:
 
3.3数据结构
class  IONode{
   String    name;
   IONode   next;
   Process   process;
   Vector  waitinglist;
   IONode   parent;
}
class   CHCT   extends   IONode{}
class   COCT   extends   IONode{}
class   DCT    extends   IONode{}

 
3.4算法设计及流程图
设备分配流程:

回收流程:

3.5小结
由于实验讲义给出了流程图,所以这个实验完成的相当快,但是理解没有很深透。


四、文件管理
4.1目的
利用磁盘文件实现操作系统的文件管理功能,主要包括目录结构的管理、外存空间的分配与释放以及空闲空间管理三部分。

4.2内容
1、	通过初始化操作建立一个模拟外存空间的虚拟磁盘文件,在该文件中保存目录和文件内容。创建该文件时应创建初始的根目录内容、文件分配表。根目录实为一特殊文件,其开始内容为空,大小为一个块。
2、	文件目录项(可以采用FCB格式)应包括类型(目录 or文件)、创建日期、大小、第一个磁盘块块号。
3、	显示命令提示符“$”,并根据输入命令完成相应的文件操作:
	MD(创建子目录):创建目录文件,并在父目录文件中增加目录项。
	CD(切换工作目录):根据当前目录切换到指定目录。
	RD(删除子目录):搜索所要删除的目录是否为空目录,若是则删除。
	MK(创建空文件):创建指定大小的文件(如输入命令 “mk  test  2000”,表示创建大小为2000字节的test文件),并在父目录中添加文件名称;还应对FAT表进行适当修改。
	DEL(删除文件):如果所要删除的文件存在,则删除,同时修改父目录内容;还应对FAT表进行适当修改。
	DIR:列出当前目录的所有目录项。
	FORMAT:根据进一步的虚拟磁盘文件名和块个数信息创建出虚拟磁盘文件。
	*TREE:根据磁盘文件和目录按着树形结构加以显示。

实验结果:
 

 
4.3数据结构
        文件储存约定:
FAT16,每个FAT表项为16位,能储存0x0000~0xffff,其中0x0000表示空,0xffff表示end of file,所以文件块最多只能有0x0000~0xfffe,共0xffff块。所以FAT表共0xffff这么多块,每块2字节。
从0x0000~0xffff*2-1=1fffc。
从0x1fffe起是第0个文件块内容,每个文件块1024字节。
由于每个文件或者文件夹有一个文件块记录FCB,这个FCB要记录它自身目录下的FCB,每个FCB占32字节。所以同级目录最多只能存1024/32=32个文件。
包括..上级目录。根目录由于直接导向0文件块,所以每个FCB都不记录。
整个磁盘文件的大小为FAT表大小0x1fffe+0xffff块文件块*1024字节文件块大小=68718690300字节,合计63GB。

虚拟磁盘文件太大了,决定缩小块数量。
每个FAT表项16位,但是FAT表只有16项,共16*2=32字节。所以最多就是16个文件或者文件夹。
第0块从0x20开始写。每块1024字节。
每个FCB依旧32字节,同级目录只能存32个,包括上级目录..。
这样整个磁盘文件为32+16*1024=16416字节,约16kb。
 

 
4.4算法设计及流程图
Md:
 
Rd:
 
CD:
 

4.5小结
做这个实验需要对文件操作熟悉。
五、进程调度
5.1目的
在1、2、3阶段实验基础上实现按先来先服务FCFS、短作业优先SJF以及时间片轮转算法调度进程的模拟过程。
5.2内容
1、	程序开始运行时选择调度算法,创建进程时输入进程所需服务时间以及到达时间。
其中,finished队列是已运行结束的进程队列,便于统计各项时间数据。
2、	根据当前所设定调度算法,连续调度所有进程,并计算每个进程的周转时间和带权周转时间、所有进程的平均周转时间和平均带权周转时间。
3、	调度时应适当输出调度过程中各进程状态队列的变化情况以及进程的已执行时间、还需服务时间(针对时间片轮转算法)。
4、	*完成银行家算法的实现。
5.3数据结构
 调度算法:
struct PCB{
	char name[10];
	int size;
	int arrival_time;		//到达时间
	int burst_time;		//服务时间
	int finished_time;	//结束运行时间
	int runned_time;		//已运行时间
	struct PCB*next;
};
struct PCB *ready,*blocked,*running,*finished;

 
银行家算法:
 
5.4算法设计及流程图
调度算法:
 
银行家算法:
 
5.5小结
调度算法之间的结合,吸取了前几个实验的教训,这次的调度算法就是高聚合低耦合。
六、课程总结
在操作系统实验过程中,不仅复习了理论课的内容,而且熟悉了常用编程语言的使用,对于文件操作,算法设计,数据处理都有不少的提高。



同时送上一张自己写的考试卷解析,考试的内容比较简单,虽然我最后只有89。。。但是卷面分应该也蛮高的,旷了几节课,期中也不好。


考试解析没有写全,不写了,等有缘人填完。


2012至2013学年第一学期 操作系统 试卷A

一、	填空题
1、	操作系统的作用是(用户与计算机硬件系统之间的接口)、(计算机系统资源的管理者)和(计算机资源的抽象)
2、	操作系统的主要功能包括5个部分,分别是(处理机)管理、(存储器)管理、(设备)管理、(文件)管理和(操作系统和用户之间的接口)
3、	根据物理存储结构的区别,将文件划分为(顺序文件)、(索引文件)和(链接文件)三类
4、	根据工作方式,I\O控制方式分为(程序I\0控制)、(中断I\O控制)、(DMA I\O控制)和(通道I\O控制)
二、	判断题
1.	在分时系统中,首先考虑的是交互性和及时性。True
2.	阻塞态是进程等待CPU调度时所处的状态。False,应该是等待I\O完成。
3.	在时间片轮转调度算法中,如时间片过小,就会引起因频繁调度而导致的调度开销太大,系统运行性能低下。True
4.	对于临界资源,进程间应当互斥访问。True
5.	虚拟存储器的实际容量是由内存容量和外存容量所决定的。False,虚拟存储器不应该说是实际容量。
6.	银行家算法是用来预防死锁的。False,用于避免死锁。
7.	动态重定位是指在程序执行时,进行逻辑地址到物理地址的转换。True
8.	必须经过处理机中转才可以实现内存和I\O设备间的数据传输。False,还有通道,通道与处理机共享内存。
9.	利用操作系统的合理控制,可以实现同一瞬间执行多个程序。False,操作系统是并发的。
10.	地址转换的目的是件物理地址转换成逻辑地址。False,正相反。
三、	单选题
1、	并发是指两个或多个事件(B)
A在同一时刻发生
B在同一时间区段内发生
C两个进程相互交互
D在时间上相互无关
2、	管道通信是利用(C)实现进程间通信
A消息
B内存
C外存文件
D邮箱
管道通信系统又名字符流通信,通过一个外存文件,pipe文件进行通信。
共享存储器系统中使用内存进行通信。
消息传递系统中使用消息进行通信,消息包括直接消息传递系统和信箱通信。
3、	在支持线程的操作系统中,一个进程至少含有(B)线程。
A 0个
B 1个
C 2个
D 3个
起码得有一个系统线程。
4、	某一时刻,某一资源的信号量s=0,它表示(D)
A该时刻该类资源的可用数目为1
B该时刻该类资源的可用数目为-1
C该时刻等待该类资源的进程数目为1
D该时刻等待该类资源的进程数目为0
整形信号量为正数时表示该时刻该类资源的可用数目,为负数时表示等待该类资源的进程数目。
5、	采用缓冲技术,能够减少对CPU的(A)次数,从而提高系统的效率。
A.	中断
B.	访问
C.	控制
D.	依赖
缓冲区的作用:
(1)	缓和CPU和I\O设备间速度不匹配的矛盾
(2)	减少对CPU的中断频率,放宽对CPU中断响应时间的限制
(3)	解决数据粒度不匹配的问题
(4)	提高CPU和I\O设备之间的并行性
6、	资源的层次分配算法在解决死锁问题中用于(A)。
A.	预防死锁
B.	避免死锁
C.	检测死锁
D.	接触死锁
资源层次分配算法是预防死锁中的破环“请求和保持”条件的方法,第一种是进程运行前必须申请全部所需资源,第二种就是资源层次分配算法。
7、	下面对临界区的论述中,正确的是(D)。
A.	临界区是指进程中用于实现进程互斥的那段代码
B.	临界区是指进程中用于实现进程同步的那段代码
C.	临界区是指进程中用于实现共享资源的那段代码
D.	临界区是指进程中访问临界资源的那段代码
对于临界资源的访问不仅仅只有互斥这一种手段。
8、	分段式存储管理系统中,地址的构成为(C)
A.	短号
B.	段内地址
C.	短号和段内地址
D.	页号
9、	在可变式分区存储管理中,某作业完成后要收回其主存空间,该空间可能与相邻空闲区合并,修改空闲区表,使空闲区数不变且空闲区起始地址改变的情况是()。
A.	无上邻空闲区也无下邻空闲区
B.	有上邻空闲区但无下邻空闲区
C.	有下邻空闲区但无上邻空闲区
D.	有上邻空闲区也有下邻空闲区
空闲区不变说明与上邻或者下邻其中一块进行了合并
空闲区起始地址改变,说明与上邻空闲区进行合并,这里的空闲区起始地址指的是回收的空闲区起始地址
10、	解决“碎片”问题最好的存储管理方法是(A)
A.	分页式存储管理
B.	分段式存储管理
C.	动态分区管理
D.	动态重地位分区管理
分页式存储管理就是为了减少碎片问题
11、	设置快表的目的在于(B)
A.	提高地址查找命中率
B.	提高地址变换速度
C.	淘汰不用的页
D.	增加页表的容量
快表是具有并行查寻能力的特殊高速缓冲寄存器,用以存放当前访问的那些页表项,目的是为了提高地址变换速度。
12、	打印机是典型的虚拟设备,其关键处理是由(D)技术实现的。
A.	中断
B.	通道
C.	缓冲
D.	SPOOLING
通过假脱机(SPOOLING)技术,则可将一台物理I\O设备虚拟为多台逻辑I\O设备,这样也就允许多个用户共享一台物理I\O设备。
13、	按用途,文件可分为用户文件、库文件和()。
A.	制度文件
B.	只写文件
C.	系统文件
D.	索引文件
14、	以下关于绝对路径和相对路径的描述中,正确的是()。
A.	绝对路径便于使用
B.	相对路径便于使用
C.	绝对路径比相对路径长
D.	相对路径便于记忆
相对路径便于使用。当在根目录时,绝对路径和相对路径一致。绝对路径便于记忆。
15、	位示图法可用于(D)
A.	文件目录的查找
B.	分段式存储管理中主存空闲块的分配和回收
C.	记录文件内容和磁盘块的分配关系
D.	分页式存储管理过程中记录内存分配与否状态
四、	简答题
1、请简述进程的3种基本状态之间的转换关系及原因
 
		2、为什么说PCB是进程存在的唯一标志
		当一个程序(含数据)配置了PCB后,就表示它已经是一个能在多道程序环境下独立运行的、合法的基本单位,也就具有取得OS服务的权利,如打开文件系统中的文件,请求获得系统中的I\O设备,以及与其他相关进程进行通信等。因此,当系统创建一个新进程时,就为它建立了一个PCB。进程结束时又回收其 PCB,进程于是也随之消亡。系统是通过PCB感知进程的存在的。事实上,PCB已经成为进程存在于系统中的唯一标志。
		3、请简述分页式存储管理的基本原理
1.按照固定大小将内存分块,按块的大小把作业分页,把各页放在内存中不连续的块中。
2.逻辑地址为【页号|页内地址】,是一维的。
3.为每一个作业建立一张页表,记录页与块的对应关系,方便地址转换。
4.地址转换,根据页号从页表中找到对应的块号,已知块长,则物理地址=块号*块长+页内地址
		4、什么是虚拟设备,该用哪种技术实现
通过虚拟技术将一台独占设备虚拟成多台逻辑设备,供多个用户进程同时使用, 通常把这种经过虚拟的设备称为虚拟设备。
使用SPOOLING技术
5、	一个块大小为4K、块号为8字节的磁盘上采用二级索引分配磁盘空间。那么该磁盘上能够创建的最大文件长度是多少?
最大文件长度=一个文件的最大块数目*块长度
一个文件用一个索引块来表示,一个索引块可以存 块大小/块号长度 个,二级索引表示,一个文件可以使用二级索引来表示,一个文件最多可以使用(一个索引块所能存块数目)^2。
所以一个文件最大能存:
(4K/8B)^2 * 4k=2^24B
五、	分析题
1、	再某一请求分页系统中,操作系统采用LRU置换算法,并为进程P分配固定的3个内存块。那么当该进程一次访问0,3,2,3,1,4,2,3,1,3,4,5,4,3,2,2,4,6,5,2页面时,共产生多少次缺页中断?如果按FIFO算法置换块,又将产生多少次缺页中断?(前三次页面的访问不计入缺页中断次数)
LRU算法:
0	3	2	3	1	4	2	3	1	3	4	5	4	3	2	2	4	6	5	2
		2	3	1	4	2	3	1	3	4	5	4	3	2	2	4	6	5	2
	3	3	2	3	1	4	2	3	1	3	4	5	4	3	3	2	4	6	5
0	0	0	0	2	3	1	4	2	2	1	3	3	5	4	4	3	2	4	6
				+	+	+	+	+		+	+			+			+	+	+
LRU缺页中断次数为11次

LRU为替换最近最久未使用的,当在内存块中存在时把该块提到栈顶,否则下面出栈,请求页面入栈。

FIFO算法:
0	3	2	3	1	4	2	3	1	3	4	5	4	3	2	2	4	6	5	2
		2	2	1	4	4	3	3	3	3	5	5	5	2	2	4	6	5	2
	3	3	3	2	1	1	4	4	4	4	3	3	3	5	5	2	4	6	5
0	0	0	0	3	2	2	1	1	1	1	4	4	4	3	3	5	2	4	6
				+	+		+				+			+		+	+	+	+
LRU缺页中断次数为9次
FIFO算法是先入先出算法,与LRU区别的是,查找到了不会把块提到栈顶。其余一致。
2、	若干个等待访问磁盘者依次要访问的柱面为20、44、40、4、80、12、76。假设刺头当前位于40号柱面(刚才在50柱面)。请按下列算法为完成上述各次访问总共花费的寻找时间。
(1)	采用先来先服务算法完成上述请求。请写出磁头移动顺序、并计算总寻道长度。
(2)	采用SSTF算法完成上述请求,请写出磁头移动的顺序,并计算总寻道长度。
(3)	采用电梯调度算法完成上述请求。请写出磁头移动的顺序,并计算总寻道长度。
FCFS算法:
先来先服务,按照顺序访问
当前磁道	移动次数
40	#
20	20
44	24
40	4
4	36
80	76
12	68
76	64
总寻道长度	292
SSTF算法:
不停访问最近的磁道
当前磁道	移动次数
40	#
40	0
44	4
20	24
12	8
4	8
76	72
80	4
总寻道长度	120
电梯调度(CSCAN)算法:
因为磁头开始在50磁道移动到40磁道,所以磁头向外移动,(0磁道在最外)
CSCAN算法会先往一个方向移动,一次访问这个方向上的磁道,然后反转方向访问。
当前磁道	移动次数
40	#
40	0
20	20
12	8
4	8
44	40
76	32
80	4
总寻道长度	112
3、	在系统的当前时刻,进程的资源请求和分配情况见下表:
进程号	进程请求资源最大向量(最大)	已分配资源向量
A	3,4,5	1,1,1
B	5,4,3	1,1,1
C	4,0,4	1,0,1
D	8,4,2	1,1,1
E	7,6,8	1,1,1
此时系统的可用资源向量为:3,5,4,试判断下述请求可否满足,并说明原因:
(1)	此时进程E申请资源,申请向量为:1,0,0
(2)	此时进程D申请资源,申请向量为:1,0,0



你可能感兴趣的:(数据结构和算法,计算机基础)