《2022年操作系统课程方案文档及代码》由会员分享,可在线阅读,更多相关《2022年操作系统课程方案文档及代码(12页珍藏版)》请在金锄头文库上搜索。
1、个人资料整理仅限学习使用1 设计目的与内容1.1 设计目的通过课程设计, 加深对操作系统对程序执行的理解, 掌握操作系统的多程序运行原理,能模拟操作系统设计相应的进程调度算法,掌握操作系统的基本原理及功能, 具有初步分析实际操作系统、设计、构造和开发现代操作系统的基本能力。1.2设计内容1、设计进程控制块PCB表结构,分别适用于可强占的优先数调度算法和循环轮转调度算法。2、建立进程就绪队列。对两种不同算法编制入链子程序。3、编制两种进程调度算法:1)可强占的优先进程调度;2)循环时间片轮转调度4、设计操作系统运行的指令。2 设计说明2.1需求分析设计虚拟内核实现进程的调度,实现多道程序的调度。
2、设计调度算法计算各个进程的优先权限来确定进程执行的次序。进程调度程序选择一个就绪状态的进程,使之在处理器上运行。进程的调度采用最高优先数优先的调度算法和先来先服务调度算法相结合的算法,并且采用动态优先数策略,选择进程占用处理器后该进程仅能使用一个时间片,运行完后优先数减1。2.2设计思路本程序用两种算法对多个进程进行调度,每个进程可有三个状态,并假设初始状态为就绪状态。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的优先数或轮转时间数以及进程需运行的时间片数的初始值均由用户给定。在优先数算法中,优先数的值为31 与运行时间的差值。进程每执行一次,优先数减1,CPU时间片数加 1
3、,进程还需要的时间片数减1。在轮转算法中,采用固定时间片 while(pcbscur_pid.state = 05 | pcbscur_pid.priority cur_pid = (cur_pid+1 % max_pid。exeInstruction(cur_pid。/ 执行指令PCB *pcb=pcbs+cur_pid。/ 获取当前进程PCB tick+。if(pcb-PC=pcb-length / 执行完毕 delete pcb-addr。/ 回收内存pcb-priority = 0。 /优先级置零pri = maxpri(。pcb-state = 05。 /将已经完成了的pcb 状态设
4、置为 05 已完成 if( pcb-last = pcb-slice pcb-last = 0。 cur_pid = (cur_pid+1 % max_pid。 可强占的优先进程调度,开始建立一个就绪队列,首先检查是否还有进程没有完毕,如果没有时间片就加 1,从就绪队列中查找一个优先级最高的进程,如果在设定的时间片内没有完成就将此进程放入就绪队列中的后面,并将优先级减1。并循环检查是否还有进程没有完成。可强占优先调度算法实现过程流程图,如图 2.1 :精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 2 页,共 12 页个人资料整理仅限学习使用图 2
5、.1 可强占优先调度算法实现过程流程图循环轮转算法实现过程,开始建立一个就绪队列,首先检查是否还有进程没有完毕,如果没有时间片就加 1,根据进程的时间片的个数运行进程。并循环检查是否还有进程没有完成。循环轮转算法实现过程流程图,如图2.2 :图 2.2 循环轮转算法实现过程流程图2.4测试2.4.1 执行多进程同时执行同一个存在的程序。两个进程的结果一样。同时执行两个存在的程序。两个进程的结果正确。同时执行3 个存在的程序。3个进程的结果正确。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 3 页,共 12 页个人资料整理仅限学习使用同时执行10
6、个进程。每个进程结果正确。同时执行10 个以上的进程。输出错误信息。输入程序名,并在后面加入要运行的用户程序,并输入初始化优先级。2.4.2 程序运行结果运行程序的优先级相同时的结果如图2.3 图 2.3 优先级相同时的结果图运行程序的优先级不相同时,高优先级运行结束后低优先级的再运行,结果如图2.4 图 2.4 优先级不相同时的结果图3 设计总结经过这次程序设计,我从中收获良多。由于是第一次接触操作系统的课程设计,在完成过程中也遇到了不少困难,本次的编程语言也选用的C+,由于最近几年都是在用java 编程,对于C+也略显生疏了。在精选学习资料 - - - - - - - - - 名师归纳总结
7、 - - - - - - -第 4 页,共 12 页个人资料整理仅限学习使用这次的实验中明显认识到要想设计出好的东西,必须要一步一步脚踏实地的去学习和了解透彻每一个知识点,这是关键,不然基本的东西都没弄清楚就盲目下手,只会对后面的设计造成不必要的麻烦,而使前面的功夫都功亏一篑,这是不值得的。每一次设计过程中,都要先弄懂此次设计的目的,所要实现的功能,并知道运用正确的算法来实现。这个过程是需要一定时间的,不是急于求成能出来的。算法可以说是编程的生命,没有一个好的算法,程序就如一个没有灵魂的人,犹如枯木,没有生机,所以算法是关键。在实现本设计过程中选用的是数组来保存进程,其实后来有想过用指针其实更
8、加利用后面算法的进行,只是因为开始所使用的数组,烦与后面的更改,就还是最终选用的数组来进行这次的设计,数组的一个好处是可以非常容易的通过下标来得到当前进程,这点是比较易于代码的编写。在基本算法想好后,后面的代码的实现就比较简单了,因为有了大一的C+基础,所以编写起来也没有什么太大的困难,总体的框架建立起来后,便是解决一些参数的调用的问题,有时候会因为一个小的参数初始化问题,或是与其他参数弄混的问题,是在调试过程中出现许多的问题。虽说是小问题,但是就是这种小问题是最难发现的,只有通过自己手动将程序在脑海中运行一遍,仔细检查每个参数是否传递正确,才能真正的检查出错误的所在,在这个时候最忌讳的就是浮
9、躁,最需要的是沉着,能真正仔细的检查,不是粗略的检查,而是将每一个函数的算法都过一遍,这样才有可能找到真正出现问题的地方,在测试过程中可通过Cout 来输出有关信息来观察出错位置。在实现多个进程并行工作并结合调度算法的实现的调试过程中出现不少问题,首先在交替执行后,一个进程执行完后,怎样让另一个进程继续执行是这个过程中遇到的一个问题,后来可通过一个count 计数来解决,并利用while 循环判断是否还有进程没有执行,从而继续执行。在并行执行过程中出现两个可以并行,有时三个也可以并行,但到第四个并行过程中出现问题,在每个函数中依次输出相关信息来验证出错地点时,发现是在ArrayPriority
10、( 函数中出错,返回的是进程的pid 而不是下标,而本程序设计中需要用得到的是最大优先级进程的下标,所以出现随机性的错误。另一个调试过程中出现的错误,也是与上面的随机性可并行的结果有关,在for 循环中进行比较时,下标的范围应该是i,因为此处要用到与i+1 比较,所以下标范围只需要小于count-1。在基本算法正确的情况下,容易被一些小问题所困扰,也是比较不容易发现的问题,就必须通过耐心的调试来得到解决。总之,在本次课程设计中,我不仅掌握了虚拟内核的建立方法,还知道了怎样通过编程来实现并行运行和基于优先级的时间片调度算法。这些是以前都没想过的,以前认为这些东西都太过于抽象,没有实际的意义,但是
11、通过课程设计,让我更加具体的了解到了操作系统的神奇之处,也更加想去深入了解到更多的知识,这也是有通过更多的自我学习来实现的,而我会继续努力学习并将理论联系实际去实现下去。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 5 页,共 12 页个人资料整理仅限学习使用参考文献1 Abraham Silberschatz. 操作系统概念( 第 8 版 影印版 . 北京:高等教育出版社,2018.2 Gary Nutt(著,潘登 ( 译.Linux操作系统内核实习. 北京:机械工业出版社,2004.3 于渊 . 自己动手写操作系统影印版) . 北京:电子工业
12、出版社,2005精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 6 页,共 12 页个人资料整理仅限学习使用附录 A 使用说明虚拟内核编译说明目标一:编译“编译程序cpl ”操作步骤: 1. 进入 cpl 文件夹 2. 双击 cpl.dsw打开工程 3. 单击菜单【组建】【批组建】,勾选【cpl-Win32 Release】,单击【创建】 4. 把 Release 文件夹里的cpl.exe复制到“测试”文件夹。目标二:编译“编译程序vknl ”操作步骤: 1. 进入 vknl文件夹 2. 双击 vknl.dsw打开工程 3. 单击菜单【组建】【批组
13、建】,勾选【vknl-Win32 Release】,单击【创建】 4. 把 Release 文件夹里的vknl.exe复制到“测试”文件夹。虚拟内核测试操作说明目标一:书写源程序用虚拟指令写源程序,计算1+2+3+4+5+6+7+8+9+10 我已经写好了,程序名为 app1.prg, 放在“测试”文件夹下,你可以用记事本打开看看。目标二:编译程序操作步骤: Windows下运行 cmd, 然后进入“测试”目录。如果你不会,就双击do.bat ) cpl app1.prg app1.bin 目标三:启动内核操作步骤: vknl app1.bin 附录 B 程序源代码程序源代码:1、 程序头文件
14、#ifndef _VIRTUAL_KERNEL_ #define _VIRTUAL_KERNEL_ 精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 7 页,共 12 页个人资料整理仅限学习使用#include iostream.h #include string.h #include stdio.h #include time.h #include #define NOP 00 /空指令 : 消耗一个机器周期#define MOV 01 / 传送指令:立即数赋值给寄存器A #define ADD 02 / 加法指令:寄存器A 加立即数#define
15、 OUT 80 /输出指令 : 寄存器 A 的值输出到端口(端口号 01-表示显示器 #define MAX_PID 10 /系统并发运行的进程数的最大值/定义 PCB 结构类型struct PCB int A 。/累加器 A int PC。/程序计数器PC char *addr。/程序加载起始地址 int length。/程序大小 int runtime 。 int waittime 。 int state。 int pname。 int pri。 /优先级数 struct PCB *next 。pcbsMAX_PID。 /* 运行指针 */ struct PCB *running 。 /*
16、 高优先级就绪队列头指针*/ struct PCB *Hready 。 /* 低优先级队列头指针*/ struct PCB *Lready 。 /* 等待队列头指针*/ struct PCB *wait 。 int sig=0 。int cur_pid 。/当前 _进程号int readyNum=MAX_PID。 /*以下是函数说明*/ /*利用循环实现延迟*/ void delay( 。 void proc(struct PCB *running 。 /* 将 node 插入到 head所指示的队列的尾部*/ void InsertIntoQueueTail(struct PCB *head
17、,struct PCB *node。 /*进程调度函数*/ int proc_switch( 。 /* 进程等待函数 */ void proc_wait( 。 /* 进程唤醒函数*/ int proc_wakeup( 。 void initSystem(void 。 /初始化系统 int loadProgram(char *name 。/加载应用程序 int exeInstruction(int pid 。/执行指令 void removeFromQueue(struct PCB *head,struct PCB *node。#endif 2、 程序文件#include vknl.h int
18、main(int argc, char *argv int i。 if(argc != 2 argv1=app1.bin。 /默认应用程序 initSystem( 。for(i=0 。i loadProgram(argvi 。 /加载应用程序 /*模拟进程调度开始*/ for(。readyNum0。 精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 8 页,共 12 页个人资料整理仅限学习使用 switch(sig case 0:/*无进程等待调度,打印信息并返回*/ if(!proc_switch( printf(No Process to run
19、,press any key to return:n。 getchar(。exit(-1。 break。 case 1:proc_wait( 。 break。 case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11:proc(running。 break。 default:printf(nerror!。 exit(-1 。 return 0。/退出虚拟内核 /初始化系统void initSystem(void cur_pid=0 。/*等待队列和高优先级队列为空*/ wait = NULL
20、 。 Hready=NULL 。 /加载应用程序int loadProgram(char *name FILE *fin=fopen(name,rb。 /打开源程序文件if(fin=NULL return -1。/若打开失败,返回-1 fseek(fin,0L,SEEK_END 。 /文件读写指针移到文件末尾long fsize=ftell(fin 。 /求文件长度fseek(fin,0L,SEEK_SET 。 /读写指针移到文件开头PCB *pcb=pcbs+cur_pid 。/获取当前进程PCB pcb-addr=new charfsize 。 /为新进程分配内存fread(pcb-add
21、r, fsize, 1, fin 。 /程序读入内存fclose(fin 。 /关闭文件pcb-length=fsize 。/进程大小pcb-A=0 。 /初始化寄存器pcb-PC=0。pcb-pname=(cur_pid+2 。 pcb-waittime=0 。pcb-state=1。 InsertIntoQueueTail(&Hready,pcb 。 /&pcbi cur_pid+ 。return 0。 /正常返回精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 9 页,共 12 页个人资料整理仅限学习使用 /执行指令int exeInstruc
22、tion(int pid PCB *pcb=pcbs+(pid-2 。/获取当前进程PCB char op_cmd=*(pcb-addr+pcb-PC 。 /取操作码short op_dat=*(short*(pcb-addr+pcb-PC+1。 /取操作数/注意 ,我们约定操作数是16 位整数,所以要定义为short。if(op_cmd=MOV /传送指令 pcb-A =op_dat 。/操作数赋给累加器A else if(op_cmd=ADD /加法指令 pcb-A +=op_dat 。/加计算 else if(op_cmd=SUB pcb-A -=op_dat 。 else if(op_
23、cmd=MUL pcb-A *=op_dat 。 else if(op_cmd=DIV pcb-A /=op_dat 。 else if(op_cmd=MOD pcb-A %=op_dat 。 else if(op_cmd=JMP printf(JMP operation. jump to %d n,op_dat。pcb-pc+= (op_dat*3 。 else if(op_cmd=OUT /输出指令 printf(OUT operation. result is %d n, pcb-A。/输出累加器A 的内容 pcb-PC+=3。/修改程序计数器 if(pcb-PC=pcb-length
24、readyNum- 。pcb-state=0。sig=0。 return 0。/正常返回 /*功能:进程 */ /*入口参数:运行指针*/ /*出口参数:无 */ void proc(struct PCB *running int i 。 if(running-state=0 return 。 /*显示当前运行的进程的id*/ printf(nNow Process %d is runningn,running-pname。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 10 页,共 12 页个人资料整理仅限学习使用 /*当前进程执行running
25、-runtime 个时间片 */ for(i=running-runtime 。i0。i- exeInstruction(running-pname 。 /*显示剩余的时间片*/ printf(%d time slice(s leftn,i。 /*延迟 */ delay(。 proc_wakeup( 。 /*产生一个1 到 1000 的随机数,若该随机数小余100,当前进程等待,*/ if(rand(%10000+1 printf(Process %d begins to wait.n,running-pname。 sig=1。 return。 /*显示时间片耗尽,进程转为低优先级就绪状态*/
26、 printf(Time slices for process %d exhausted.n,running-pname。 InsertIntoQueueTail(&Lready,running。 sig=0。 return。 /*功能:将一个节点插入队列尾部*/ /*入口参数:队列头指针地址head,待插入结点node*/ /*出口参数:无 */ void InsertIntoQueueTail(struct PCB *head,struct PCB *node struct PCB *p 。 node-next=NULL 。 if(*head=NULL /*被插入队列为空*/ *head=
27、node。 return。 /*被插入队列不为空*/ else p=*head。 /*找到队列的最后一个结点*/ while(p-next!=NULL p=p-next。 p-next=node。 /*功能:进程调度*/ /*入口参数:无 */ /*出口参数:若调度成功,返回1,否则返回0*/ int proc_switch( /*若高优先级就绪队列和低优先级就绪队列均为空,则循环执行进程唤醒*/ while(Hready=NULL&Lready=NULL if(!proc_wakeup( return 0 。 /*若高优先级就绪队列非空,则执行其第一个进程,分配2 个时间片 */ if(Hr
28、eady!=NULL running = Hready 。 Hready=Hready-next 。 running-runtime=2 。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 11 页,共 12 页个人资料整理仅限学习使用 /*若高优先级就绪队列为空,则执行低优先级就绪队列的第一个进程,分配 5个时间片 */ else running=Lready 。 Lready=Lready-next 。 running-runtime=5 。 /*别调度进程的id 赋给 sig*/ sig=running-pname 。 return 1。 /*功能:进程等待。将当前运行进程置高优先级,等待时间为20,插入等待队列尾部*/ /*入口参数:无 */ /*出口参数:无 */ void proc_wait( PCB *p 。 running-pri=1 。 running-waittime=20 。 InsertIntoQueueTail(&wait,running。 sig=0。 return。 /*功能:进程唤醒*/ 精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 12 页,共 12 页