第一篇:进程创建实验报告
实验二 进程的创建
一、实验目的
熟悉进程的创建过程,了解系统调用函数fork()和 execl()。
二、实验内容
1、阅读实例代码fork1,并编辑、编译、运行,记录程序的运行结果,尝试给出合理的解释,查阅有关资料,掌握系统调用fork()的用法,返回值的意义。
2、阅读实例代码fork2,并编辑、编译、运行,记录程序的运行结果,尝试给出合理的解释,查阅有关资料,掌握在程序中运行一个操作系统命令和运行一个程序的方法。
3、修改fork2,使之能把运行的命令和程序作为参数传给fork2。
三、设计思想
1、程序框架
pid =-1 pid = 0 pid > 0
2、用到的文件系统调用函数 fork()和 execl()
四、调试过程
1、测试数据设计(1)fork1 命名程序1:
编写程序1:
编译程序1:
运行程序1:
(2)fork2 编写程序2:
运行程序2:
(3)修改fork2 编写修改程序2:
修改后的运行结果:
2、测试结果分析
(1)对于程序1:因为系统调用fork()函数是一次调用两次返回值,而且先生成子进程还是父进程是不确定的,所以第一次执行生成子进程的时候返回的pid = 0,判断pid!=-1,所以输出了I’m the child.I’m the parent.第二次,执行父进程的时候,返回的是子进程的进程号pid > 0,即pid的值仍然不为-1,所以又输出了一次I’m the child.I’m the parent。
(2)对于程序2:第一次调用fork()函数时,由于执行的是子进程还是父进程是随机的,所以第一次对父进程返回的是子进程的进程号(大于0),即pid > 0,所以输出I’m the parent.Program end.当第二次执行子进程时返回值是0,即pid = 0,所以输出I’m the child.并调用了execl()函数,查看了指定路径中的文件。
(3)对于修改后的程序2:改变了系统调用execl()中参数的文件路径和可执行文件名,即可在程序fork2.c中执行另一个程序wyf.c(但要注意可执行文件名是123)。
五、总结
1、调试过程中遇到的主要问题及解决过程
运行程序2的时候如果不加execl()函数的头文件
2、体会和收获
通过这次实验我进一步熟悉了linux系统,也学会了进程的创建过程和返回值的意义。同时学会了一个新的系统调用函数execl()及其头文件和参数类型。也学会了在编写完程序之后,不仅可以用 :wq 保存并退出,也可以用快捷键 shift + zz。
六、附录:源程序代码(另附)
第二篇:进程调度实验报告
天津大学仁爱学院
实验类型:实验名称:实验地点:
学生姓名:班 级:
操作系统 实验报告
必 修 实验日期:2014年4月18日进程调度 二实验楼504 李帅帅 指导教师:张 磊 计科一班 计算机科学与技术系
天津大学仁爱学院——计算机科学与技术系——李帅帅
实验报告内容:
1)实验目的
用c语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
2)实验器材和设备
硬 件: 二实验楼504计算机
开发工具: Microsoft Visual C++ 6.0
3)实验任务
本实验模拟单处理器系统的进程调度,加深对进程的概念及进程调度算法的理解。用c语言编写和调试一个进程调度的算法程序,有一些简单的界面,能够运行,仿真操作系统中进程调度的原理和过程。通过对调度算法的模拟,进一步理解进程的基本概念,加深对进程运行状态和进程调度
4)实验原理
无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数、这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。
基本状态:1.等待态:等待某个事件的完成;
2.就绪态:等待系统分配处理器以便运行; 3.运行态:占有处理器正在运行。
运行态→等待态 往往是由于等待外设,等待主存等资源分配或等待人工干预而引起的。
等待态→就绪态 则是等待的条件已满足,只需分配到处理器后就能运行。运行态→就绪态 不是由于自身原因,而是由外界原因使运行状态的进程让出处理器,这时候就变成就绪态。例如时间片用完,或有更高优先级的进程来抢占处理器等。
就绪态→运行态 系统按某种策略选中就绪队列中的一个进程占用处理器,此时就变成了运行态
5)实验过程描述
a)打开Microsoft Visual C++ 6.0,创建工程。
b)根据要求用 c语言代码实现应用程序,并调试完成。c)运行程序,根据提示输入相应的字符。
d)输入实验测试内容,并观察执行窗口显示的过程。
天津大学仁爱学院——计算机科学与技术系——李帅帅
q=(struct pcb *)malloc(sizeof(pcb));
cin>>q->name;
cin>>q->needtime;
q->cputime=0;
q->priority=P_TIME-q->needtime;
q->process=ready;
q->next=NULL;
if(i==0)
{
p=q;
t->next=q;
}
else
{
q->next=t->next;
t=q;
q=p;
}
i++;} return p;}
void display(pcb * p){ cout<<“name”<<“ ”<<“cputime”<<“needtime”<<“ ”<<“priority”<<“ ”
<<“state”< cout< name; cout<<“ ”; cout< cputime; cout<<“ ”; cout< needtime; cout<<“ ”; cout< priority; cout<<“ ”; switch(p->process) { case ready:cout<<“ready”< case execute:cout<<“execute”< case block:cout<<“block”< case finish:cout<<“finish”< } 天津大学仁爱学院——计算机科学与技术系——李帅帅 void priority_cal(){ pcb * p;system(“cls”);p=get_process();int cpu=0;system(“cls”);while(!process_finish(p)){ cpu++; cout<<“cuptime:”< cpuexe(p); display(p); Sleep(1000);} printf(“All processes have finished,press any key to exit”);getch();} void display_menu(){ cout<<“nCHOOSE THE ALGORITHM:”< pcb *get_process_round(){ pcb *q;pcb *t;pcb *p;int i=0;t=(struct pcb *)malloc(sizeof(pcb));p=(struct pcb *)malloc(sizeof(pcb));cout<<“input name and time”< cin>>q->name; cin>>q->needtime; q->cputime=0; 天津大学仁爱学院——计算机科学与技术系——李帅帅 { } } return t;} void set_state(pcb *p){ while(p){ if(p->needtime==0) { p->process=finish;//如果所需执行时间为0,则设置运行状态为结束 } if(p->process==execute) { p->process=ready;//如果未执行状态则设置为就绪 } p->next;} }//设置队列中进程执行状态 void display_round(pcb *p){ cout<<“NAME”<<“ ”<<“CPUTIME”<<“ ”<<“NEEDTIME”<<“ ”<<“COUNT”<<“ ”<<“ROUND” <<“ ”<<“STATE”< cout< name; cout<<“ ”; cout< cputime; cout<<“ ”; cout< needtime; cout<<“ ”; cout< count; cout<<“ ”; cout< round; cout<<“ ”; switch(p->process) { case ready:cout<<“ready”< case execute:cout<<“execute”< case finish:cout<<“finish”< 天津大学仁爱学院——计算机科学与技术系——李帅帅 7)实验结果截图 1.进程状态: 1)可运行状态(TASK_RUNNING) 2)可中断的等待状态(TASK_INTERRUPTIBLE) 3)不可中断的等待状态(TASK_UNINTERRUPTIBLE) 4)暂停状态(TASK_STOPPED) 5)僵死状态(TASK_ZOMBIE) 2.进程的创建:1)fork:使用该系统调用时,子进程复制父进程的全部资源。由于要复制父进程进程描述符给子进程(进程描述的结构很大!),这一过程开销是很大的。linux采用了”写时复制技术”(copy on write,COW),使子进程先共享父进程的物理页,只有子进程进行写操作时,再复制对应的物理页,避免了无用的复制开销,提高了系统的性能。 实现代码(x86):arch/x86/kernel/process.c int sys_fork(struct pt_regs *regs) { Return do_fork(SIGCHLD, regs->sp, regs,0, NULL, NULL); } 2)vfork:该系统调用创建的子进程,完全运行在父进程地址空间之上。子进程对地址空间任何数据的修改同样为父进程所见。vfork执行后父进程堵塞,知道子进程运行结束。 实现代码(x86):arch/x86/kernel/process.c int sys_vfork(struct pt_regs *regs) { Return do_fork(CLONE_VFORK | CLONE_VM |SIGCHLD, regs->sp, regs, 0,NULL, NULL); } 3)clone:该调用是linux系统所特有的,其NPTL的实现依赖此函数。与fork,vfork相比clone对进程创建有更好的控制能力,能控制子进程和父进程共享何种资源。 实现代码(x86):arch/x86/kernel/process.c long sys_clone(unsignedlong clone_flags, unsigned long newsp,void__user *parent_tid, void__user *child_tid, structpt_regs *regs){ if(!newsp) newsp = regs->sp; Return o_fork(clone_flags, newsp, regs, 0,parent_tid, child_tid);} 上面进程的创建最终依赖于:do_fork(),只是向其传递了不同的参数clone_flags,其原型为: long do_fork(unsigned long clone_flags,unsigned long stack_start,struct pt_regs *regs,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr) 参数分析: clone_flags:低字节指定子进程结束时发送到父进程的信号代码,通常选择SIGCHLD信号。剩余3个字节给一clone标志组用于编码 stack_start:子进程用户态堆栈的地址 regs:指向内核态堆栈通用寄存器值的指针,通用寄存器的值是在从用户态切换到内核态时被保存到内核态堆栈中的。 stack_size:未使用,总被设置为0。 parent_tidptr:表示父进程的用户态变量地址,该父进程具有与新轻量级进程相同的PID。 child_tidptr:表示新轻量级进程的用户态变量地址,该进程具有这一类进程的PID。只有在CLONE_CHILD_SETTID被设置时才有意义。 而do_fork()函数生成一个新的进程,大致分为三个步骤。 1、建立进程控制结构并赋初值,使其成为进程映像。 2、必须为新进程的执行设置跟踪进程执行情况的相关内核数据结构。包括任务数组、自由时间列表 tarray_freelist 以及 pidhash[] 数组。 3、启动调度程序,使子进程获得运行的机会。 实验报告说明书 设计名称: 操作系统课程设计 实 验 : 进程调度设计 学生姓名: 专 业: 网络工程 班 级: 08级一班 学 号: 指导教师:雷晓平王东 黄营 杨跃武 日 期: 2011年 6月 19日 课程设计任务书 网络工程 专业 08 年级 1 班 一、具体要求 本课程设计共2周,采取集中方式。㈠主要设计内容 1、进程调度 2、存储管理 3、文件管理 ㈡操作系统分项设计 1、设计一 :进程管理系统设计 目的与要求:本设计的目的是加深对进程概念及进程管理各部分内容的理解;熟悉进程管理中主要数据结构的设计及进程调度算法、进程控制机构、同步机构及通讯机构的实施。 要求设计一个允许n个进程并发运行的进程管理模拟系统。该系统包括有简单的进程控制、同步与通讯机构,其进程调度算法可任意选择。每个进程用一个PCB表示,其内容根据具体情况设置。各进程之间有一定的同步关系(可选)。系统在运行过程中应能显示或打印各进程的状态及有关参数的变化情况,以便观察诸进程的运行过程及系统的管理过程。 具体详见:设计任务书1--进程调度算法.doc 2、设计二:存贮器管理系统设计 目的与要求:本设计的目的是使学生熟悉存贮器管理系统的设计方法;加深对所学各种存贮器管理方案的了解;要求采用一些常用的存贮器分配算法,设计一个存贮器管理模拟系统并调试运行。模拟环境应尽量接近真实。 具体详见:设计任务书2--内存分区管理模拟.doc 3、设计三:虚拟存储器管理系统设计 本设计的目的是通过设计一个简单的虚拟存储器管理系统来模拟实际的页面调度算法与过程,以掌握这种有用的技术。要求将其输入/输出处理程序编成一个独立的进程模块并与其它请求输入/输出的进程并发运行。并要求加入设备管理子模块。 具体分析为:页面调度算法主要有FIFO、最近最少使用调度算法(LRU)、最近最不常用调度算法(LFU)、最佳算法(OPT)等。题目要求: ① 实现三种算法: 1、先进先出; 2、OPT; 3、LRU ② 页面序列从指定的文本文件(TXT文件)中取出 ③ 输出:第一行:每次淘汰的页面号,第二行:显示缺页的总次数 4、设计四:文件管理系统设计 目的与要求:本设计的目的是通过设计和调试一个简单的外部文件系统,主要是模拟文件操作,使学生对主要文件操作命令的实质和执行过程有比较深入的了解,掌握它们的基本实施方法。 基本要求如下: 实现三种算法: 先来先服务、最短寻道优先、电梯算法 磁道服务顺序从指定的文本文件(TXT文件)中取出 输出:第一行:磁道的服务顺序;第二行:显示移动总道数 5、设计五:多道程序的转换调度系统 题目要求:(作业调度和进程调度结合在一起)作业流信息是从指定文本文件(TXT文件)中读取 作业信息: 作业号 进入系统时间 估计运行时间 优先级 内存需求量 磁带机需求量 都为整型 作业调度算法:先来先服务、最短作业优先(二者选一) 进程调度算法:先来先服务、基于优先级的算法(静态优先级)(二者选一)输出格式:作业号 时间间隔 800-810(/* 8:00-8:10 */)2 810-900 1 900-930平均周转时间:总的周转时间/作业总数 周转时间就是作业结束时间减去作业进入系统时间 具体详见:多道程序转换.doc 以上设计以20-25人为组,选择一个设计进行。㈢操作系统整体设计 将第㈡部分中的全部或部分有机地组合起来,构成一个小型的操作系统。 二、进度安排 1、教师下达设计任务书(半天)任务书内容包括题目、主要技术指标和要求、给定条件及原始数据、所用仪器设备和参考资料及文献等。教师讲授必要的设计思路和设计方法。 2、学生完成预设计(1天半)本阶段学生通过查阅资料及文献(主要自学),明确任务,掌握工程设计基本方法,确定设计方案,进行设计分析,完成预设计。 3、实验阶段(7天)经教师审查通过预设计方案后,即可进行编程调试。实验由学生独立完成,教师定时指导。 4、设计总结阶段(1天)本阶段学生要认真完成课程设计报告书,整理技术资料,并尽可能写出课程设计的心得体会和改进意见。 三、完成后应上交的材料 课程设计报告书包括:设计任务及主要技术指标、设计方案及论证结果、系统的原理框图、设计程序、实验结果、实验中主要问题及故障现象的分析及设计结论等。 附实验数据、系统软硬件环境、使用说明及参考资料。 四、总评成绩 指导教师 签名日期 年 月 日 系 主 任 审核日期 年 月 日 目 录 一、实验目的………………………………………5 二、实验要求………………………………………5 三、具体内容………………………………………5 3.1先来先服务(FCFS)„„„„„„„5 3.2作业优先SJF 算法„„„„„„„„5 3.3多级队列调度算法„„„„„„„„.5 3.4时间片轮转调度法„„„„„„„„„5 3.5优先级法„„„„„„„„„„„„„6 3.6多队列反馈法„„„„„„„„„„„6 3.7轮转法„„„„„„„„„„„„„„.6 3.8最短周期优先„„„„„„„„„„„6 3.9先来先服务„„„„„„„„„„„„„7 四、实验程序………………………………………7 五、实验总结………………………………………13 设计题目:进程管理系统设计 一、实验目的: 本设计的目的是加深对进程概念及进程管理各部分内容的理解;熟悉进程管理中主要数据结构的设计及进程调度算法、进程控制机构、同步机构及通讯机构的实施。 二、实验要求: 设计一个允许n个进程并发运行的进程管理模拟系统。该系统包括有简单的进程控制、同步与通讯机构,其进程调度算法可任意选择。每个进程用一个PCB表示,其内容根据具体情况设置。各进程之间有一定的同步关系(可选)。系统在运行过程中应能显示或打印各进程的状态及有关参数的变化情况,以便观察诸进程的运行过程及系统的管理过程。 三、具体内容: 调度也称dispatcher,这是内核的主要职责之一。一个良好的任务调度算法应该主要体现在以下几个方面: 公平:保证每个进程得到合理的CPU 时间 高效:使CPU 保持忙碌状态,即总是有进程在CPU 上运行 响应时间:使交互用户的响应时间尽可能短 周转时间:使批处理用户等待输出的时间尽可能短 吞吐量:使单位时间内处理的进程尽可能多 很显然在任何操作系统中这几个目标不可能同时达到所以不同的。 操作系统会在这几个方面中做出相应的取舍从而确定自己的调度算法,常用的处理机调度算法有:先来先服务FCFS、短作业优先SJF、优先级、时间片轮转法、多级队列法、多级反馈队列法。 (1)先来先服务(FCFS) FCFS 是最简单的CPU 调度算法,即按进程到来的先后次序进行调度,这样在系统中等待时间最长的进程被优先调度,而不管其所需运行时间的长短。 (2)作业优先SJF 算法 是指当CPU 可供使用时SJF 算法把CPU 分给需要运行时间最短的进程。(3)多级队列调度算法 把就绪队列划分成几个单独的队列一般根据进程的某些特性如内存大小和进程类型永久性地把各个进程分别链入其中某一个队列中,每个队列都有自己的调度算法,此外在各个队列之间也要进行调度。通常采用固定优先级的抢占式调度,例如某系统中有5 个队列,各个队列的优先级自上而下降低,只有当前3 个队列中都为空的时候队列4 中的进程才可以运行,而当队列4 中的进程在运行时,如果队列1 中进入了一个就绪进程,则队列4 中的进程要立刻让出CPU 使用权。多级反馈队列法允许进程在各队列间移动,其基本思想是把具有不同CPU工作时间这一特性的进程区分开来,如果一个进程要使用很长的CPU 时间,则应把它移至较低级的队列中,这种方式把I/O 繁忙型和交互式进程放在较高优先级的队列中同样在低优先级队列中长时间等待的进程可以移到较高优先级队列中UNIX 系统采用的是多级反馈队列轮转法。 (4)时间片轮转调度法 当两个或两个以上任务有同样优先级,内核允许一个任务运行事先确定的一段时间叫做时间额度quantum,然后切换给另一个任务也叫做时间片调度time slicing,内核在满足以下条件时把CPU 控制权交给下一个任务就绪态的任务,当前任务已无事可做,当前任务在时间片还没结束时已经完成了。轮转法主要是为分时系统设计的,其中时间片是一个重要的参数不能取的过大或过小,通常为10 至100ms 数量级,就绪队列可以看成是一个环形队列,CPU 调度程序轮流 地把CPU 分给就绪队列中地每个进程,时间长度为一个时间片Linux 操作系统就是采用时间片轮转的调度算法。 (5)优先级法 优先级调度的基本思想是,把当前处于就绪队列中优先级最高的进程投入运行,而不管各进程的下一个CPU周期的长短和其他因素。 优先级通常用0~4095的整数(称为优先数)表示,是数大优先级高还是数小优先级高取决于规定。例如UNIX系统规定优先数越大优先级越低,优先数越小优先级越高。 优先数有静态和动态之分。静态优先数是指在进程开始运行之前便根据某种或某些因素(如估计运行时间、主存需求量、打开文件个数、所付经费多少等)算定,而且该优先数在进程的整个生命周期内一直不变。静态优先数方法虽然简单,但有可能导致某些低优先级的进程无限期地等待。尤其在高优先级的进程不断进入就绪队列的情况下,使等待CPU的低优先级进程更多,等待时间更长。动态优先数方法是按照某种原则使各进程的优先级随着时间而改变。例如随等待时间增大优先级也跟着提高、随着使用CPU时间的增长优先级跟着下降,就是一种较好的策略。等待了较长时间的进程,总会因其优先级不断地提高而被调度运行。 如果把进入就绪队列的次序作为计算进程动态优先数的主要指标,那么优先级法就变成FCFS。如果把下一个CPU周期最短作为计算进程动态优先数的主要指标,那么优先级法变成SBF,此时各进程的优先数p_pri = 1/ ti,其中ti是估算的下一个CPU周期的长度。 优先级调度也允许剥夺方式。现在的许多操作系统,例如UNIX系统V,Windows NT,OS/2等都采用优先级剥夺调度。 (6)多队列反馈法 其基本思想是,把就绪进程按优先级排成多个队列,同队列的进程具有相同的时间片。高优先级队列的时间片比低优先级队列的小。调度时先从高优先级队列中选出某一进程投入运行,当该进程的时间片到期后则转至低一级的就绪队列中。只有高优先级队列为空时才从低一级队列中调度进程。 例如考虑由3个队列组成的多级队列调度。3个队列的编号分别为0, 1, 2,如图所示。调度算法首先调度0号队列中的进程。当0号队列为空时才调度1号队列中的进程;当0号与1号队列都为空时才调度2号队列中的进程。在剥夺方式下,新进入0号队列的进程将剥夺1号或2号队列中正在执行的进程的CPU,而新进入1号队列的进程将剥夺2号队列中正在执行的进程的CPU。 其实,每个队列都可拥有各自的调度算法,也可制定不同的“转队”规则。这样看来,多队列反馈调度算法能有多种变化。 (7)轮转法 轮转法就是按一定时间片(记为q)轮番运行各个进程。如果q是一个定值,则轮转法是一种对各进程机会均等的调度方法。 轮转法本质上是剥夺的,因为一轮内,每个进程不能获得比一个时间片q更长的运行时间。正是由于这一特点,轮转法特别适用于分时操作系统。 轮转法的关键问题是如何确定q的大小。如果时间片太大以致每个进程的CPU周期都能在一个时间片内完成,则轮转法实际上脱化为FCFS。如果q太小以致CPU切换过于频繁,则会增加CPU的额外开销,降低了CPU的有效利用率。这是因为,每次CPU切换涉及到保存原运行进程的现场和恢复新运行进程的现场,这些操作一般需要10ms~100ms的时间。例如,设有一个CPU周期为10单位的进程,在q取12,6,1时的调度次数分别为0,1,9。令时间单位为1ms(1ms=1000ms),1次调度的开销为100ms,则在q=1时CPU的额外开销和有效开销之比为1:10,这是不容忽视的。 (8)最短周期优先 最短周期优先(SBF: shortest burst first)把当前就绪队列中的下一个CPU周期最短的那个进程调度运行。 (9)先来先服务 如果早就绪的进程排在就绪队列的前面,迟就绪的进程排在就绪队列的后面,那么先来先服务(FCFS: first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的下一个CPU周期的长短及其他因素。FCFS算法简单易行,但性能却不大好。 四、实验程序 #include “iostream.h” //define pcb typedef struct pcb { char name[10];//进程名 char state;//状态w(就绪)r(运行)f(结束)int id;//id号 int super;//优先级 int ntime;//需运行的时间 int rtime;//已运行的时间 struct pcb *next;}*pcb1; pcb1 s,w;//define two publiced linknode ,one is s(ready queue),one is w(blocked queue) //initialize two queues void init(pcb1 &r){ r=NULL;//both queues is the kind of head index } //print the information of the ready queue void print(){pcb1 p;cout<<“您现在查看的是就绪队列的信息:”;cout<<“进程号 ”<<“进程名 ”<<“优先级 ”<<“状态”<<“已运行时间 ”<<“需运行时间”< cout< id<<“ ”< name<<“ ”< super<<“ ”< state<<“ ”< rtime<<“ ”< ntime< //print the information of the blocked queue void print1(){pcb1 p;cout<<“您现在查看的是阻塞队列的信息”;cout<<“进程号 ”<<“进程名 ”<<“优先级 ”<<“状态 ”<<“已运行时间 ”<<“需运行时间”< id<<“ ”< name<<“ ”< super<<“ ”< state<<“ ”< rtime<<“ ”< ntime< //check the queue if empty int empty(pcb1 &r){ if(r==NULL)return 0;else return 1;} //check the first process of the ready queue if finshed int check(){ pcb1 p;p=s;if(p->rtime==p->ntime){ p->state='F';//if one process finshed then change ti's state cout<<“进程”< id<<“ 已经结束”< //sort process according to the super of the process and insert to the ready(blocked)queue void sort(pcb1 &r,pcb1 p){ pcb1 p1,p2;int in=0;if(r==NULL)//the queue is empty { r=p;} else { if(p->super>=r->super)//the super of the process which wait insert to the queue is highter than the super of the first process of the queue { p->next=r;r=p;} else { p1=r;p2=r->next;if(p2==NULL)//only one process in the queue { r->next=p;} else { while(in==0&&p2!=NULL)//insert to the middle of the queue { if(p->super>=p2->super){ p->next=p2;p1->next=p;in=1;} else { p1=p1->next;p2=p2->next;} } } if(in==0)//link to the last of ready queue p1->next=p;} } } //block one process and insert to block queue void block(){ if(empty(s)){ if(s->next==NULL){ sort(w,s);s=s->next;} else { pcb1 p1;p1=s;s=s->next;p1->next=NULL;sort(w,p1);} } else { cout<<“现在就绪队列已经为空,再没有进程需要阻塞”< //wake one process of block queue and insert to ready queue void wake(){ if(empty(w)){ pcb1 p1;p1=w;w=w->next;p1->next=NULL;sort(s,p1);} else { cout<<“阻塞队列已经为空,没有进程再需要唤醒”< //runing void runing(){ if(empty(s)){ pcb1 p;p=s;if(check())//check the first process of the queue if finished {//no s=s->next;p->rtime++;p->super--;p->next=NULL;sort(s,p);} else {//yes s=s->next;} } else { cout<<“就绪队列已经为空”< //creat process void input(){ pcb1 p2;p2=new pcb;cout<<“请输入 进程号、进程名、进程优先级、需要运行时间”;cin>>p2->id>>p2->name>>p2->super>>p2->ntime;p2->rtime=0;p2->state='W';p2->rtime=0;p2->next=NULL; sort(s,p2);} //main function void main(){ char ch;init(s);init(w);cout<<“*****************************进程调度模拟程序开始*******************************”< 程序运行界面如下: 五、实验总结 本次实验,我的任务是设计一个允许n个进程并发运行的进程管理模拟系统。该系统包括有简单的进程控制、同步与通讯机构,系统在运行过程中能显示各进程的状态及有关参数的变化情况,从而观察诸进程的运行过程及系统的管理过程,我是用C++写的,在我的电脑能够运行通过,虽不能尽善尽美,但也基本能实现老师的要求。 两个星期程序设计课程,虽然时间有点短,但我也收获不少,这次试验,加深了我对进程概念及进程管理的理解;比较熟悉进程管理中主要数据结构的设计及进程调度算法、进程控制机构、同步机构及通讯机构的实施。也让我认识到自己的不足,操作系统的有些知识,我知道的还不多,没有掌握好,还需要多多学学,不断提升自己的能力。 进程调度算法模拟 专业:XXXXX 学号:XXXXX 姓名:XXX 实验日期:20XX年XX月XX日 一、实验目的 通过对进程调度算法的模拟加深对进程概念和进程调度算法的理解。 二、实验要求 编写程序实现对5个进程的调度模拟,要求至少采用两种不同的调度算法分别进行模拟调度。 三、实验方法内容 1.算法设计思路 将每个进程抽象成一个控制块PCB,PCB用一个结构体描述。 构建一个进程调度类。将进程调度的各种算法分装在一个类中。类中存在三个容器,一个保存正在或未进入就绪队列的进程,一个保存就绪的进程,另一个保存已完成的进程。还有一个PCB实例。主要保存正在运行的进程。类中其他方法都是围绕这三个容器可以这个运行中的PCB展开。 主要用到的技术是STL中的vector以维护和保存进程容器、就绪容器、完成容器。 当程序启动时,用户可以选择不同的调度算法。然后用户从控制台输入各个进程的信息,这些信息保存到进程容器中。进程信息输入完毕后,就开始了进程调度,每调度一次判断就绪队列是否为空,若为空则系统时间加一个时间片。判断进程容器中是否有新的进程可以加入就绪队列。2.算法流程图 主程序的框架: 开始void FCFS();//先来先服务void SJF();//最短进程优先调度void RR();//简单时间片轮转void PD();//最高优先数优先void PCBInput();//输入进程信息选择调度算法输入进程信息将输入容器中以满足进入条件的进程调入就绪队列void ProcessQueueProcess();//查看当前时间下,有无进程加入。若有则把该进程调入就绪队列按照选择的算法开始选择就绪队列的进程开始执行void ProcessSelect();//若当前就绪队列不为空则根据选择的调度算法开始调度,否则,系统时间加一个时间片.以等待新的进程到判断就绪容器和输入容器是否为空!processScheduler.m_WaitQueue.empty()||!processScheduler.m_ProcessQueue.empt()Y打印各进程信息进行统计计算周转时间等结束void PCBDisplay();//打印当前状况下。就绪队列、完成队列、运行中的进程信息void SchedulerStatistics();//调度统计,计算周转时间等进程调度过程: 开始为空判断就绪队列是否为空if(m_WaitQueue.empty())非空让系统等待一个时间片TimePast()根据设定的调度算法从就绪队列中调入一个进程并执行(此时进程从就绪队列中删除,赋值到表示运行中的成员变量中)void FCFS();//先来先服务void SJF();//最短进程优先调度void RR();//简单时间片轮转void PD();//最高优先数优先进程运行一个时间片N是否达到该进程停止运行的条件Y选入的进程状态是否为“完成”如进程已完成,或者分得的时间片个数已到ProcessRun()Yvector m_WaitQueue;//进程就绪队列进程未完成,将进程优先数减一,并放回到就绪队列中设置进程完成时间,将该进程放入完成队列vector m_FinishQueue;//完成队列结束 3.算法中用到的数据结构 struct fcfs{ //先来先服务算法从这里开始 char name[10]; float arrivetime; float servicetime; float starttime; float finishtime; float zztime; float dqzztime; }; //定义一个结构体,里面包含的有一个进程相关的信息 4.主要的常量变量 vector m_ProcessQueue;//进程输入队列 vector m_WaitQueue;//进程就绪队列 vector m_FinishQueue;//完成队列 vector ::iterator m_iter;//迭代器 PCB m_runProcess;//运行中的进程 int m_ProcessCount;//进程数 float m_RunTime;//运行时间 int m_tagIsRun;//是否在运行标志。表示正在运行,表示没有 float m_TimeSlice;//时间片大小 int m_TimeSliceCount;//指时间片轮转中一次分到的时间片个数 char m_SchedulerAlgorithm;//调度算法 5.主要模块 void PCBInput();//输入进程信息 void PCBSort();//对进程控制块按照优先级排序(采用冒泡排序)void ProcessSelect();//若当前就绪队列不为空则根据选择的调度算法开始调度。否则,系统时间void PCBDisplay();//打印当前状况下。就绪队列、完成队列、运行中的进程信息 void ProcessRun();//进程运行一次。运行时间加个时间片。并判断进程是否达到完成条件。若是则void ProcessQueueProcess();//查看当前时间下,有无进程加入。若有则把该进程调入就绪队列 void ProcessDispatch();//进程分派,进程执行完成后决定进程该进入哪个队列(就绪、完成)void TimePast(){ m_RunTime +=m_TimeSlice;ProcessQueueProcess();}//当前系统时间加个时间void SchedulerStatistics();//调度统计,计算周转时间等 void FCFS();//先来先服务 void SJF();//最短进程优先调度 void RR();//简单时间片轮转 void PD();//最高优先数优先 加.以等待新的进程到来 ProcessStatus='f'.否则为'w';片,并检查是否有新的进程加入 四、实验代码 #include using namespace std; struct fcfs{ //先来先服务算法从这里开始 char name[10]; float arrivetime; float servicetime; float starttime; float finishtime; float zztime; float dqzztime; }; //定义一个结构体,里面包含的有一个进程相关的信息 fcfs a[100]; void input(fcfs *p,int N) { int i; cout< printf(“ 请您输入进程的名字 到达时间 服务时间:(例如: a 0 100)nn”); for(i=0;i<=N-1;i++) { printf(“ 请您输入进程%d的信息:t”,i+1); scanf(“ttt%s%f%f”,&p[i].name,&p[i].arrivetime,&p[i].servicetime); } } void Print(fcfs *p,float arrivetime,float servicetime,float starttime,float finishtime,float zztime,float dqzztime,int N) { int k; printf(“nn调用先来先服务算法以后进程运行的顺序是: ”); printf(“%s”,p[0].name); for(k=1;k { printf(“-->%s”,p[k].name); } cout< printf(“n 具体进程调度信息:n”); printf(“t进程名 到达时间 服务时间 开始时间 结束时间 周转时间 带权周转时间n”); for(k=0;k<=N-1;k++) { printf(“t%st%-.2ft %-.2ft %-.2ft %-.2ft %-.2ft %-.2fn”,p[k].name,p[k].arrivetime,p[k].servicetime,p[k].starttime,p[k].finishtime,p[k].zztime,p[k].dqzztime); } getchar(); //此处必须要有这个函数,否则就看不到显示器上面的输出,可以看到的结果只是一闪而过的一个框剪 } void sort(fcfs *p,int N)//排序 { for(int i=0;i<=N-1;i++) for(int j=0;j<=i;j++) if(p[i].arrivetime { fcfs temp; temp=p[i]; p[i]=p[j]; p[j]=temp; } } void deal(fcfs *p, float arrivetime,float servicetime,float starttime,float finishtime,float &zztime,float &dqzztime,int N) //运行阶段 { int k; for(k=0;k<=N-1;k++) { if(k==0) { p[k].starttime=p[k].arrivetime; p[k].finishtime=p[k].arrivetime+p[k].servicetime;} else { p[k].starttime=p[k-1].finishtime; p[k].finishtime=p[k-1].finishtime+p[k].servicetime;} } for(k=0;k<=N-1;k++) { p[k].zztime=p[k].finishtime-p[k].arrivetime; p[k].dqzztime=p[k].zztime/p[k].servicetime; } } void FCFS(fcfs *p,int N) { float arrivetime=0,servicetime=0,starttime=0,finishtime=0,zztime=0,dqzztime=0; sort(p,N); deal(p,arrivetime,servicetime,starttime,finishtime,zztime,dqzztime,N); Print(p,arrivetime,servicetime,starttime,finishtime,zztime,dqzztime,N); getchar(); } //先来先服务算法到此结束 struct sjf{//最短进程优先调度算法从这里开始 char name[10];float arrivetime;//到达时间 float servicetime;//运行时间 float starttime; //开始时间 float finishtime; //完成时间 };sjf a1[100]; void input(sjf *p,int N1)//进程信息输入 { int i;cout< printf(“ 请您输入进程的名字 到达时间 服务时间:(例如: a 0 100)n”); for(i=0;i<=N1-1;i++){ printf(“ 请您输入进程%d的信息:t”,i+1); scanf(“ttt%s%f%f”,&p[i].name,&p[i].arrivetime,&p[i].servicetime);} } void Print(sjf *p,float arrivetime,float servicetime,float starttime,float finishtime,int N1)//最终结果输出 { int k; printf(“nt调用最短进程优先调度算法以后进程的调度顺序为:”); printf(“%s”,p[0].name); for(k=1;k {printf(“-->%s”,p[k].name);} cout< printf(“n给个进程具体调度信息如下:n”); printf(“nt进程名t到达时间t运行时间t开始时间t完成时间n”); for(k=0;k<=N1-1;k++) { printf(“ t%st %-.2ftt %-.2ftt %-.2ftt %-.2ftn”,p[k].name,p[k].arrivetime,p[k].servicetime,p[k].starttime,p[k].finishtime); } getchar(); } void sort(sjf *p,int N1)//排序 { for(int i=0;i<=N1-1;i++) for(int j=0;j<=i;j++) if(p[i].arrivetime { sjf temp; temp=p[i]; p[i]=p[j]; p[j]=temp; } } void deal(sjf *p, float arrivetime,float servicetime,float starttime,float finishtime,int N1)//运行阶段 { int k; for(k=0;k<=N1-1;k++) { if(k==0) { p[k].starttime=p[k].arrivetime; p[k].finishtime=p[k].arrivetime+float(p[k].servicetime)/60;} else { p[k].starttime=p[k-1].finishtime; p[k].finishtime=p[k-1].finishtime+float(p[k].servicetime)/60;} } } void sjff(sjf *p,int N1){ float arrivetime=0,servicetime=0,starttime=0,finishtime=0; sort(p,N1); for(int m=0;m {if(m==0) p[m].finishtime=p[m].arrivetime+float(p[m].servicetime)/60; else p[m].finishtime=p[m-1].finishtime+float(p[m].servicetime)/60; int i=0; for(int n=m+1;n<=N1-1;n++) { if(p[n].arrivetime<=p[m].finishtime) i++; } float min=p[m+1].servicetime; int next=m+1; for(int k=m+1;k { if(p[k+1].servicetime {min=p[k+1].servicetime; next=k+1;} } sjf temp; temp=p[m+1]; p[m+1]=p[next]; p[next]=temp; } deal(p,arrivetime,servicetime,starttime,finishtime,N1); Print(p,arrivetime,servicetime,starttime,finishtime,N1); getchar();}//最短进程优先调度算法到这里结束 char menu()//用来输出相关信息的函数 { char cse1; while(1) { system(“cls”); fflush(stdin); cout< cout< cout<<“t”<<“|| <<<<<<<<<<<<欢<<<<<<<<<<< >>>>>>>>>>>>迎>>>>>>>>>>> ||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“t 进程调度算法模拟”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“tt 1.先来先服务调度算法 ”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“tt 2.最短进程优先调度算法”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“|| <<<<<<<<<<<<<<<<<<<<<<<<<您>>>>>>>>>>>>>>>>>>>>>>>>> ||”< cout< cout< cout<<“tt 请输入您的选择(1/2):”; cse1=getchar(); if(cse1<'1'||cse1>'2') cout<<“你的输入有错!”< else break; } return cse1;} int main(int argc, char *argv[]){ while(1) { switch(menu()) { case '1': int N; cout< cout< printf(“tt<<---!!@@@先来先服务调度算法@@@!!--->>n”); cout< printf(“输入进程数目:”); scanf(“%d”,&N); input(a,N); FCFS(a,N); case '2': int N1; cout< cout< printf(“tt<<---!!@@@最短进程优先调度算法@@@!!--->>n”); cout< printf(“输入进程数目: ”); scanf(“%d”,&N1); input(a1,N1); sjf *b=a1; sjf *c=a1; sjff(b,N1); getchar(); } } system(“PAUSE”); return EXIT_SUCCESS;} 五、实验结果 1.执行结果 2.结果分析 先来先服务调度算法就是根据进程达到的时间为依据,哪一个进程先来那么该进程就会先执行;最短进程优先调度算法则是以每个进程执行所需时间长短为依据,某一个进程执行所需花的时间要短些那么该进程就先执行。以上就是本次进程调度实验的依据。 六、实验总结 通过本次实验了解到算法很重要,又更加明白算法本身可以节约时间,而且不同的函数之间在调用的时候要注意很多的问题。第三篇:进程创建函数分析
第四篇:操作系统进程管理系统设计实验报告
第五篇:操作系统进程调度算法模拟实验报告