精华内容
下载资源
问答
  • 操作系统课程设计实验报告-可变分区存储管理和多级队列调度算法模拟实现 (34页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!19.90 积分操作系统课程设计报告姓名学号...

    操作系统课程设计实验报告-可变分区存储管理和多级队列调度算法模拟实现

    (34页)

    本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!

    19.90 积分

    操作系统课程设计报告姓名学号班级院系日期指导教师实验一可变分区存储管理一、实验要求设计合理的数据结构来描述存储空间对于未分配出去的部分,可以用空闲分区队列来描述,对于已经分配出去的部分,由装入内存的作业占据,可以将作业组织成链表或数组。实现分区存储管理的内存分配功能,要求选择至少两种适应算法(如首次适应算法,最佳适应算法,最后适应算法,最坏适应算法)。实现分区存储管理的内存回收算法要求能够正确处理回收分区与空闲分区的四种邻接关系。当碎片产生时,能够进行碎片的拼接。二、设计目的在掌握了计算机可变分区存储管理方式的原理的基础上,利用C语言在WINDOWS操作系统下模拟实现操作系统的可变分区存储管理的功能,以便加深对可变分区存储管理原理的理解,提高根据已有原理通过编程解决操作系统实际问题的能力,另一方面提高根据已有原理通过编程解决实际问题的能力,为进行系统软件开发和针对实际问题提出高效的软件解决方案打下基础。三、各功能模块分析实现需要设计合理的数据结构来描述存储空间,包括被程序占用的存储空间、空闲的存储空间、多个程序的组织。通常用链表把这些同种类型的存储空间连接起来,使用结构体来描述每个存储空间的属性信息。根据可变分区存储管理的基本原理,程序的实现主要包括以下几个部分1内存的初始化包括确定内存的起始地址、内存的大小等。2要进入内存的程序链表的产生多个要进入内存运行的程序的产生,包括程序编号、所占存储空间的大小。可以把这些内容以记录式文件的形式保存到磁盘上,也可以把他们存放在二维数组中。若保存在文件中,则可以多次使用,如保存在数组中只能使用一次。3为程序分配存储空间可以采用首次适应、最佳适应、最后适应算法来实现。主要是按照这三种算法的思想对空闲块进行排序,以便找出符合要求的那个空闲块。对空闲块的排序思路可以使用冒泡排序算法的思想。4记录和显示内存被程序占用的情况5记录和显示内存中空闲块的情况6回收存储空间程序运行完毕后,要及时回收内存空间。四、主程序流程图STEP’1’STEP’2’STEP’6’STEP’3’STEP’4’STEP’5’STEP’7’创建分区头节点删除上次的结果文件键盘输入字符STEP字符STEP为EXITPUTJOBINTOMEMORYFINISHJOBSHOWCURRENTFREELISTSHOWCURRENTMEMORYUSEDBYJOBSMOVEFRAGMENTTOGETHERINITIALIZIATION五丶主要实验代码VOIDINIT//初始化,设置物理内存中用户区的大小,选取适应算法{FLNULL//将各值复位ALNULLJLNULLUSERMEMORY0FITALGORITHM0COUNT0PRINTF“\N请设置用户区的大小(整型)“CINUSERMEMORYSETFITALGORITHMFNODETMPFNODEMALLOCSIZEOFFNODETMPSTARTADDRESS0TMPSIZEUSERMEMORY//初始化时,将整个用户内存划分到一个分区里TMPLASTNULLTMPNEXTNULLFLTMP}VOIDSETFITALGORITHM//设置适应算法{FITALGORITHM0WHILEFITALGORITHM4||FITALGORITHMFITALGORITHM}DOFITALGORITHM}VOIDDOFITALGORITHM//执行适应算法{FNODETFNODEMALLOCSIZEOFFNODEINTTMPSTARTADDRESS0INTTMPSIZE0FORFNODEIFLINULLIINEXT{TIFORFNODEJINEXTJNULLJJNEXT{SWITCHFITALGORITHM{CASE1{IFJSIZESIZE//最佳适应算法,找到链表中分区大小最小的分区{TJ}BREAK}CASE2{IFJSIZETSIZE//最坏适应算法,找到链表中分区大小最大的分区{TJ}BREAK}CASE3{IFJSTARTADDRESSSTARTADDRESS//首次适应算法,找到链表中分区起始地址最小的分区{TJ}BREAK}CASE4{IFJSTARTADDRESSTSTARTADDRESS//最后适应算法,找到链表中分区起始地址最大的分区{TJ}BREAK}}}TMPSTARTADDRESSISTARTADDRESS//将剩余链中找到的分区交换到剩余链的最前端TMPSIZEISIZEISTARTADDRESSTSTARTADDRESSISIZETSIZETSTARTADDRESSTMPSTARTADDRESSTSIZETMPSIZE}}VOIDADDJOB//添加作业{INTNUM0INTSIZE0PRINTF“\N“PRINTF“请输入要加入的作业的编号(整型)“CINNUMPRINTF“请输入要加入的作业的大小(整型)“CINSIZECOUNTJNODEJOBJNODEMALLOCSIZEOFJNODE//初始化一个新作业结点JOBIDCOUNTJOBNUMNUMJOBSIZESIZEJOBSTATUS0JOBLASTNULLJOBNEXTNULLIFJLNULL//将新作业加入作业链表中{//若JL链为空,则直接将JL指向该结点JLJOB}ELSE{//若JL不为空,则将该结点插入JL链的前端JOBNEXTJLJLLASTJOBJLJOB}DOFITALGORITHM//在进行内存分配之前需执行适应算法IFALLOCATEMEMORYJOB0//开始内存分配{PRINTF“\N没有足够的内存空间分配給该作业\N“}ELSE{PRINTF“\N该作业成功得到内存分配\N“}}INTALLOCATEMEMORYJNODETMP//内存分配{INTFLAG0//用于标记新作业是否能被分配,0为不能FORFNODEIFLINULLIINEXT{IFISIZETMPSIZE//找到一个符合要求的分区装入作业{TMPSTATUS1//更改作业状态为已装入内存ANODETANODEMALLOCSIZEOFANODE//初始化新加入的已分配分区结点TJIDTMPIDTSIZETMPSIZETSTARTADDRESSISTARTADDRESSTLASTNULLTNEXTNULLIFALNULL//将已分配的分区接入已分配分区链表中{//若AL链为空,则直接将AL指向该结点ALT}ELSE{//若AL不为空,则将该结点插入AL链的前端TNEXTALALLASTTALT}IFISIZETMPSIZE{//若该分区大小大于作业大小,则将剩余大小重新赋给该分区ISTARTADDRESSISTARTADDRESSTMPSIZEISIZEISIZETMPSIZE}ELSE{//若该分区大小恰好等于作业大小,则从空闲分区链表中删除该分区IFILASTNULL{FLINEXT}ELSEIFINEXTNULL{ILASTNEXTNULL}ELSE{ILASTNEXTINEXTINEXTLASTILAST}DELETEI}FLAG1BREAK}}RETURNFLAG}VOIDFINISHJOB//完成作业{JNODEJOBJNODEMALLOCSIZEOFJNODEINTFLAG0//用于标记该ID是否存在,0为不存在INTID0PRINTF“\N请输入要完成的作业的ID(整型)“CINIDFORJNODEIJLINULLIINEXT//找出该ID的作业{IFIIDID{JOBIFLAG1BREAK}}IFFLAG0{PRINTF“\N该ID不存在\N“}ELSE{IFJOBLASTNULL//将已完成的作业从作业链表中删除{JLJOBNEXT//若该JOB为链表头结点,则JL链表直接指向其下一个结点}ELSEIFJOBNEXTNULL{JOBLASTNEXTNULL}ELSE{JOBLASTNEXTJOBNEXTJOBNEXTLASTJOBLAST}DELETEJOBDEALLOCATEMEMORYID//开始内存回收PRINTF“\N该作业成功完成\N“}}VOIDDEALLOCATEMEMORYINTJID//内存回收{ANODEAANODEMALLOCSIZEOFANODEINTSTARTADDRESS//待合并分区的起始地址INTENDADDRESSFORANODEIALINULLIINEXT//找到该作业所占的已分配分区{IFIJIDJID{AIBREAK}}STARTADDRESSASTARTADDRESSENDADDRESSSTARTADDRESSASIZE1IFALASTNULL{ALANEXT}ELSEIFANEXTNULL{ALASTNEXTNULL}ELSE{ALASTNEXTANEXTANEXTLASTALAST}DELETEAMERGEMEMORYSTARTADDRESS,ENDADDRESS//传入待合并分区的起始地址}VOIDMERGEMEMORYINTSTARTADDRESS,INTENDADDRESS//合并分区{FNODELSNULLFNODENSNULLFNODETFNODEMALLOCSIZEOFFNODETSTARTADDRESSSTARTADDRESSTSIZEENDADDRESSSTARTADDRESS1TLASTNULLTNEXTNULLFORFNODEIFLINULLIINEXT{IFENDADDRESS1ISTARTADDRESS{//查找与其结束地址后相邻的空闲分区NSI}IFISTARTADDRESSISIZESTARTADDRESS{//查找与其起始地址前相邻的空闲分区LSI}}IFLSNULL}ELSE{TNEXTFLFLLASTTFLT}}IFLSNULL}IFLSNULLNSSIZENSSIZETSIZE}IFLSNULL}ELSEIFNSNEXTNULL{//若NS为尾结点,则直接将该结点删除NSLASTNEXTNULL}ELSE{NSLASTNEXTNSNEXTNSNEXTLASTNSLAST}LSSIZELSSIZETSIZENSSIZEDELETENS}}VOIDDEFRAGMENT//碎片整理,进行碎片拼接{INTSUM0//记录已分配空间的总大小FORANODEIALINEXTNULLIINEXT{ISTARTADDRESSINEXTSIZEINEXTSTARTADDRESS//更改已分配分区的起始地址,将这些分区的地址移到内存的低址部分SUMSUMISIZE}IFFLNULL//FL不为空表示还存在空闲空间,否则不存在空闲空间{FLNEXTNULL//将剩余的空闲分区合并为一个分区FLSTARTADDRESSSUMFLSIZEUSERMEMORYSUM}PRINTF“\N碎片拼接完成\N“}VOIDRELOAD//重新装入作业链中未装入内存的作业{FORJNODEIJLINULLIINEXT{IFISTATUS0{DOFITALGORITHM//在进行内存分配之前需执行适应算法IFALLOCATEMEMORYI0//开始内存分配{PRINTF“\N没有足够的内存空间分配給D号作业\N“,IID}ELSE{ISTATUS1PRINTF“\ND号作业成功得到内存分配\N“,IID}}}}VOIDSHOWFLIST//显示当前空闲分区链的信息{PRINTF“\N“PRINTF“当前空闲分区链信息\N“PRINTF“分区起始地址分区大小\N“FORFNODEIFLINULLIINEXT{PRINTF“10D“,ISTARTADDRESSPRINTF““PRINTF“|10D“,ISIZEPRINTF“\N“}PRINTF“\N“PRINTF“\N“}VOIDSHOWALIST//显示当前已分配分区链的信息{PRINTF“\N“PRINTF“当前已分配分区链信息\N“PRINTF“分区起始地址分区大小分区作业号\N“FORANODEIALINULLIINEXT{PRINTF“10D“,ISTARTADDRESSPRINTF““PRINTF“|10D“,ISIZEPRINTF““PRINTF“|10D“,IJIDPRINTF“\N“}PRINTF“\N“PRINTF“\N“}VOIDSHOWJLIST//显示当前作业链的信息{PRINTF“\N“PRINTF“当前作业链信息\N“PRINTF“作业ID作业编号作业大小作业状态\N“FORJNODEIJLINULLIINEXT{PRINTF“10D“,IIDPRINTF““PRINTF“|10D“,INUMPRINTF““PRINTF“|10D“,ISIZEPRINTF““IFISTATUS0{PRINTF“|未装入内存“}ELSE{PRINTF“|已装入内存“}PRINTF“\N“}PRINTF“\N“PRINTF“\N“}VOIDMAINPAGE//主界面{INTI0PRINTF“\N“PRINTF“主界面\N“PRINTF“1初始化(设置物理内存中用户区的大小,选取适应算法)\N“PRINTF“2作业进入内存(内存分配)\N“PRINTF“3作业完成(内存回收)\N“PRINTF“4显示当前空闲分区链的信息\N“PRINTF“5显示当前已分配分区链的信息\N“PRINTF“6显示当前作业链的信息\N“PRINTF“7碎片整理(碎片拼接)\N“PRINTF“8重新装入未装入内存的作业\N“PRINTF“9显示所有链的信息\N“PRINTF“10设置适应算法\N“PRINTF“0退出\N“PRINTF“\N“INTMAINVOID{MAINPAGERETURNSYSTEM“PAUSE“}六丶实验截图进行初始化选择最佳适应算法添加3个作业显示空闲分区显示当前已分配分区链信息显示当前作业链信息完成作业1和2显示当前空闲分区进行拼接后显示分区操作系统课程设计报告1七丶实验小结通过本次课程设计,自己的编程能力有所提高,对操作系统内存的分配,存储空间的回收,以及碎片的拼接都有了全新的认识。在这次操作系统的课程设计我使用了C语言编写系统软件,对OS中可变分区存储管理有了更深刻的理解。通过验证,可以说是做出结果。但是过程中遇到很多困难,只能边做边查资料,问同学。也许是程序的某个边界的设计不合理。在教案中提供了双向链表的实现方法,但是感觉对于性能提升影响不大,但是对于编程复杂度提高较多,实际做下来感觉这个方法比较鸡肋。通过试验,对于C的语句有了比较多的了解,我们原来学的是C,但是发现C的I/O比于C的似乎更为简便一些。任何输入而正常结束。很遗憾的是因为时间问题,没有把这个模拟程序写成动画形式,还可以加几句代码后实现动态的增加作业。总而言之,究其原因还是自己平时没学牢固。希望在以后的学习中可以学到更多知识。操作系统课程设计报告2实验二多级队列调度算法模拟实现1设计要求在熟练掌握计算机处理机调度原理的基础上,利用一种程序设计语言模拟实现多级反馈队列进程调度算法,一方面加深对原理的理解,另一方面提高学生通过编程根据已有原理解决实际问题的能力,为学生将来进行系统软件开发和针对实际问题提出高效的软件解决方案打下基础。调度算法中采用至少4级队列,每级队列的时间片大小预先指定。由于只是模拟实现,调度的对象进程实际上并不包括程序和数据,而仅仅包括一个PCB数据结构,用PCB来代表一个进程,调度算法调度的对象只包括进程的PCB处理机的切换通过将PCB在运行指针和就绪队列之间进行移动来实现。又因为进程的组成只有PCB,没有程序和数据,因而进程只有运行和就绪两种状态,没有等待状态。为避免显示结果超过1屏,调度结果要求写入文件中以方便检验。2基础知识由于处理机是计算机系统中最宝贵和稀有的资源,因而处理机调度是操作系统进行资源管理的一个重要功能。现代操作系统广泛采用多道程序设计的技术来提高系统吞吐量,提高程序的并发度和资源利用率。特别是进程调度程序,由于其运行频率高,更加要求调度算法简单,高效,系统开销小,进程切换快,可以说,调度算法的好坏直接影响整个计算机系统的性能。多级队列调度算法是一种动态优先数调度算法。对于普通的优先调度算法,如何确定进程优先级以真实地反映进程运行的紧迫程度是一个难题,但在多级队列调度算法中,可以预先规定优先级一样可以获得好的性能。该算法实际上综合了两种调度算法队列内部是FCFS,队列之间是优先调度。3数据结构参考最核心的数据结构就是进程的逻辑结构。进程中必须包括的内容很多(参见教材PCB部分的定义),为了简化起见,可以略去一些与本模拟调度算法关系不大的一些信息。请同学们自行设计,要求能够实现本调度算法即可。操作系统课程设计报告34主程序流程图初始化输入A;A2N创建进程YA2N撤消进程A3N阻塞进程YYA4唤醒进程NYA0退出系统YN终止A=ENTER执行进程N操作系统课程设计报告45程序运行截图此系统的界面是在DOS界面下输出的,所以以下的输出结果均是DOS界面截图。初始化界面创建进程依次创建进程A,B,C和所需时间。运行进程操作系统课程设计报告5进程运行结束6实验关键代码INTMAINVOID{PRIOCREATEPROCESSCREATEMULTIDISPATCHOUTPUTRETURN0}VOIDOUTPUT{READYQUEUEPRINTHEAD操作系统课程设计报告2PCBPPRINTF“进程名\T优先级\T轮数\TCPU时间\T需要时间\T进程状态\T计数器\N“WHILEPRINT{IFPRINTLINKPCBNULL{PPRINTLINKPCBWHILEP{PRINTF“S\TD\TD\TD\TD\T\TC\T\TD\N“,PNAME,PPRIO,PROUND,PCPUTIME,PNEEDTIME,PSTATE,PCOUNTPPNEXT}}PRINTPRINTNEXT}PFINISHWHILEPNULL{PRINTF“S\TD\TD\TD\TD\T\TC\T\TD\N“,PNAME,PPRIO,PROUND,PCPUTIME,PNEEDTIME,PSTATE,PCOUNTPPNEXT}PRUN操作系统课程设计报告3WHILEPNULL{PRINTF“S\TD\TD\TD\TD\T\TC\T\TD\N“,PNAME,PPRIO,PROUND,PCPUTIME,PNEEDTIME,PSTATE,PCOUNTPPNEXT}}VOIDINSERTFINISHPCBIN{PCBFSTFSTFINISHIFFINISHNULL{INNEXTFINISHFINISHIN}ELSE{WHILEFSTNEXTNULL{FSTFSTNEXT操作系统课程设计报告4}INNEXTFSTNEXTFSTNEXTIN}}VOIDINSERTPRIOREADYQUEUEIN{READYQUEUEFST,NXTFSTNXTHEADIFHEADNULL{INNEXTHEADHEADIN}ELSE{IFINPRIOFSTPRIO{INNEXTHEADHEADIN}ELSE操作系统课程设计报告5{WHILEFSTNEXTNULL{NXTFSTFSTFSTNEXT}IFFSTNEXTNULL{INNEXTFSTNEXTFSTNEXTIN}ELSE{NXTININNEXTFST}}}}VOIDPRIOCREATE{READYQUEUETMP操作系统课程设计报告6INTIPRINTF“输入就绪队列的个数\N“SCANF“D“,PRINTF“输入每个就绪队列的CPU时间片\N“FORI0IROUNDTMPPRIO50TMPROUNDTMPLINKPCBNULLTMPNEXTNULLINSERTPRIOTMP}}VOIDGETFIRSTREADYQUEUEQUEUE{RUNQUEUELINKPCB操作系统课程设计报告7IFQUEUELINKPCBNULL{RUNSTATE'R'QUEUELINKPCBQUEUELINKPCBNEXTRUNNEXTNULL}}VOIDINSERTLASTPCBIN,READYQUEUEQUEUE{PCBFSTFSTQUEUELINKPCBIFQUEUELINKPCBNULL{INNEXTQUEUELINKPCBQUEUELINKPCBIN}ELSE{WHILEFSTNEXTNULL{FSTFSTNEXT操作系统课程设计报告8}INNEXTFSTNEXTFSTNEXTIN}}VOIDPROCESSCREATE{PCBTMPINTIPRINTF“输入进程的个数\N“SCANF“D“,PRINTF“输入进程名字和进程所需时间\N“FORI0INAMEGETCHARSCANF“D“,操作系统课程设计报告9TMPCPUTIME0TMPSTATE'W'TMPPRIO50TMPNEEDTIMETMPROUNDHEADROUNDTMPCOUNT0INSERTLASTTMP,HEAD}}VOIDROUNDRUNREADYQUEUETIMECHIP{INTFLAG1GETFIRSTTIMECHIPWHILERUNNULL{WHILEFLAG{RUNCOUNTRUNCPUTIMERUNNEEDTIMEIFRUNNEEDTIME0{操作系统课程设计报告10RUNSTATE'F'INSERTFINISHRUNFLAG0}ELSEIFRUNCOUNTTIMECHIPROUND{RUNSTATE'W'RUNCOUNT0INSERTLASTRUN,TIMECHIPFLAG0}}FLAG1GETFIRSTTIMECHIP}}VOIDMULTIDISPATCH{INTFLAG1INTK0READYQUEUEPOINTPOINTHEAD操作系统课程设计报告11GETFIRSTPOINTWHILERUNNULL{OUTPUTIFHEADLINKPCBNULLPOINTHEADWHILEFLAG{RUNCOUNTRUNCPUTIMERUNNEEDTIMEIFRUNNEEDTIME0{RUNSTATE'F'INSERTFINISHRUNFLAG0}ELSEIFRUNCOUNTRUNROUND{RUNSTATE'W'RUNCOUNT0IFPOINTNEXTNULL操作系统课程设计报告12{RUNROUNDPOINTNEXTROUNDINSERTLASTRUN,POINTNEXTFLAG0}ELSE{ROUNDRUNPOINTBREAK}}KIFK3{PROCESSCREATE}}FLAG1IFPOINTLINKPCBNULLPOINTPOINTNEXTIFPOINTNEXTNULL{ROUNDRUNPOINT操作系统课程设计报告13BREAK}GETFIRSTPOINT}}操作系统课程设计报告27实验总结多级反馈队列调度算法又称反馈循环队列或多队列策略,主要思想是将就绪进程分为两级或多级,系统相应建立两个或多个就绪进程队列,较高优先级的队列一般分配给较短的时间片。处理器调度先从高级就绪进程队列中选取可占有处理器的进程,只有在选不到时,才从较低级的就绪进程队列中选取。使用这种调度策略具有较好的性能,能够满足各类用户的需要。此系统简单模拟实现多级反馈队列调度算法,但是只是人为的模拟多线程实现处理器的分配,没有真正地实现多线程,只是单执行流过程。在这次操作系统中,使我对操作系统中进程的概念,进程的状态转换,线程的概念和多线程实现对处理器分配的基本原理有了更加深刻的理解。其中也体现了我的不足(1)系统冗余代码过多。为了实现在DOS下表格的制作,使用了一些特殊的表格线而非利用C语言中的画图功能,频繁的进行光标定位和结果输出,冗余代码过多,浪费系统资源。(2)算法效率较低。算法的实现都只考虑到效果的实现,而算法的效率则次之。(3)使用DOS界面运行程序而非可视化窗口界面。(4)为了实现模拟的效果而采用了些低效率的做法,如对进程的状态切换直接使用删除、插入进程节点的方法,而非利用指针定位实现状态的切换,使系统每次运行相关程序时,都要大量地执行删除、插入等操作,降低了系统的性能。 关 键 词: 操作系统 课程设计 实验 报告 可变 分区 存储 管理 多级 队列 调度 算法 模拟 实现

     天天文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。

    关于本文

    本文标题:操作系统课程设计实验报告-可变分区存储管理和多级队列调度算法模拟实现

    链接地址: https://www.wenku365.com/p-6810070.html

    展开全文
  • 用java编写的一个调度算法,是计算机操作系统里的一个算法的演示程序 附源代码和设计报告
  • 多级反馈队列进程调度GUI实现,使用Swing编写的一个可视化界面,支持进程的动态创建,进程调度过程可视化。
  • 二、多级反馈队列调度算法简介 三、需求分析和设计 四、代码实现 1. 进程控制块类 2. 控制块队列类 3. 多级反馈队列进程调度模拟类 五、相关说明 ​不得不说,利用IDEA的GUI Form对Swing的支持,使得...

    ​不得不说,利用IDEA的GUI Form对Swing的支持,使得我们可以直接在一个没有父类的(也就是不用继承JFrame)的普通类起步来构建我们的GUI Application。不得不承认,虽然现在IDEA对于Swing的“所见即所得”的拖拉控件可视化做的没有NetBeans好,虽然我们可以直接在NetBeans上直接拖拉控件然后点击相应控件来添加我们的逻辑,但是对于真正的开发人员来说却有一个现象,他们很少使用“拖拉拽”这种“傻瓜式的”添加控件的方式,他们大多都是通过Swing中的布局管理器来组织他们所添加的控件,并调用Swing中布局管理器的相应API和控件本身的API来控制控件的布局。


    ​ 有过Android开发经验的朋友应该知道,为什么Android的AbsoluteLayout(绝对布局)已经被人抛弃,早已过时。因为这种布局管理器根本没有提供什么“布局管理”的支持,它其实就像Swing中你为某个Container调用“setLayout(null);”一样,它需要我们通过X、Y坐标来控制控件的摆放位置。也许我们在模拟机上试出了漂亮的界面,到了真机测试才发现“这是什么啊”!运行Android应用的手机往往千差万别,因此屏幕分辨率、屏幕大小一般都存在较大差异,使用绝对布局很难兼顾不同屏幕分辨率、大小的问题。由此我们也不难解释上面的现象了。


    ​ 之所以使用IDEA来开发Swing, 还有一个重要的原因,就是所需代码量极少!你可以先使用NetBeans编写一个带有一个按钮的简单的GUI界面(不管你使用“拖拉拽”还是纯粹手工编写,当然“脱拉拽”会生成“一大坨”额外的布局代码,看着很难受),然后看看我下面使用IDEA编写的代码:

    /*
     * @program: MFQ
     * @description:
     * @author: WuchangI
     * @create: 2018-05-24-08-48
     **/
    
    import javax.swing.*;
    public class Testing
    {
        private JButton button;
        private JPanel panel;
        public static void main(String[] args)
        {
            JFrame frame = new JFrame("Testing");
            frame.setContentPane(new Testing().panel);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(1000, 800);
            frame.setVisible(true);
        }
    }
    

    好处很明显,也不用多讲。


    ​ 除此之外,IDEA的.form文件帮我们封装了Swing控件的一些布局信息(自动生成的),有点像Android的.xml布局文件,不像NetBeans那样将业务逻辑和布局显示都混在一起(有点out了),体现了MVC的应用,这样有利于专注我们业务逻辑的实现。

    一、效果预览

    前面讲了那么多废话,马上使用IDEA来实现这个MFQ(multi-level feedback queues),这里先看看效果:

    1



    二、多级反馈队列调度算法简介

    无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数, 这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。因此,我们需要用到一些调度方式来解决进程互相争夺资源,使得每个进程都很好的使用的处理机。


    多级反馈队列调度算法 就是一种CPU处理机调度算法,是目前公认的较好的一种进程调度算法,它能较好的满足各类进程的需要,UNIX操作系统采取的便是这种调度算法。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。具体实现如下:

    1. 应设置多个就绪队列,并为各个队列赋予不同的优先级。

      第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。

    2. 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n队列中便采取按时间片轮转的方式运行。

    3. 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行; 仅当第1~(i-1) 队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。



    三、需求分析和设计

    采用多级反馈队列调度算法进行进程调度的模拟。

    • 每个进程对应一个 PCB。在 PCB 中包括进程标识符 pid、进程的状态标识 status、进程优先级 priority、表示进程生命周期的数据项 life(在实际系统中不包括该项)。
    • 创建进程时即创建一个 PCB,各个进程的 pid 都是唯一的,pid 是在 1 到 100 范围内的一个整数。
    • 可以创建一个下标为 1 到 100 的布尔数组, “假”表示下标对应的进程标识号是空闲的,“真”表示下标对应的进程标识号已分配给某个进程。
    • 进程状态 status 的取值为“就绪 ready”或“运行 run”,刚创建时,状态为“ready”。被进程调度程序选中后变为“run”。
    • 进程优先级 priority 是 0(最低) 到 49(最高) 范围内的一个随机整数。
    • 进程生命周期 life 是 1 到 5 范围内的一个随机整数。
    • 初始化时,创建 50 个就绪队列,各就绪队列的进程优先级 priority 分别是 0 到 49。
    • 为了模拟用户动态提交任务的过程,要求动态创建进程。进入进程调度循环后,每次按 ctrl+f 即动态创建一个进程,然后将该 PCB 插入就绪队列中。
    • 在进程调度循环中,每次选择优先级大的就绪进程来执行。将其状态从就绪变为运行,通过延时一段时间来模拟该进程执行一个时间片 的过程,然后优先级减半,生命周期减一。
    • 如果将该运行进程的生命周期不为 0,则重新把它变为就绪状态,插入就绪队列中;否则该进程执行完成,撤消其 PCB。以上为一次进程调度循环。
    • 设计图形用户界面 GUI,在窗口中显示该进程和其他所有进程的 PCB 内容。



    四、代码实现

    1. 进程控制块类

    Code:

    PCB.java

    package com.wuchangi;
    
    /*
     * @program: MFQ
     * @description: PCB
     * @author: WuchangI
     * @create: 2018-05-20-22-04
     **/
    
    //进程控制块类
    public class PCB
    {
        //进程标识符
        private int pid;
    
        //进程状态标识
        private String status;
    
        //进程优先级
        private int priority;
    
        //进程生命周期
        private int life;
    
        public PCB()
        {
        }
    
        public PCB(int pid, String status, int priority, int life)
        {
            this.pid = pid;
            this.status = status;
            this.priority = priority;
            this.life = life;
        }
    
        public int getPid()
        {
            return pid;
        }
    
        public void setPid(int pid)
        {
            this.pid = pid;
        }
    
        public String getStatus()
        {
            return status;
        }
    
        public void setStatus(String status)
        {
            this.status = status;
        }
    
        public int getPriority()
        {
            return priority;
        }
    
        public void setPriority(int priority)
        {
            this.priority = priority;
        }
    
        public int getLife()
        {
            return life;
        }
    
        public void setLife(int life)
        {
            this.life = life;
        }
    }


    2. 控制块队列类

    Code:

    PCBsQueue.java

    package com.wuchangi;
    
    /*
     * @program: MFQ
     * @description: PCBsQueue
     * @author: WuchangI
     * @create: 2018-05-23-13-49
     **/
    
    import java.util.LinkedList;
    
    //控制块队列类
    class PCBsQueue
    {
        //队列优先级
        private int priority;
        private LinkedList<PCB> queue = new LinkedList<PCB>();
    
    
        public PCBsQueue(int priority)
        {
            this.priority = priority;
        }
    
        public int getPriority()
        {
            return priority;
        }
    
        public void setPriority(int priority)
        {
            this.priority = priority;
        }
    
        public LinkedList<PCB> getQueue()
        {
            return queue;
        }
    
        public void setQueue(LinkedList<PCB> queue)
        {
            this.queue = queue;
        }
    }


    3. 多级反馈队列进程调度模拟类

    Code:

    MFQSimulation.java

    
    package com.wuchangi;
    
    /*
     * @program: MFQ
     * @description: MFQSimulation
     * @author: WuchangI
     * @create: 2018-05-20-22-04
     **/
    
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.InputEvent;
    import java.util.Arrays;
    import java.util.LinkedList;
    
    
    public class MFQSimulation
    {
        private static JFrame frame = new JFrame("进程调度模拟(多级反馈队列)");
        private static JPanel panel = new JPanel();
        private static JScrollPane scrollPane = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    
        //菜单组件
        private static JMenuBar menuBar = new JMenuBar();
        private static JMenu processSettingsMenu = new JMenu("Process Settings");
        private static JMenuItem createProcessItem = new JMenuItem("Create A Process");
        private static JMenuItem startMFQItem = new JMenuItem("Start Scheduling");
        private static JMenuItem stopMFQItem = new JMenuItem("Stop Scheduling");
        private static JMenuItem setTimeSliceItem = new JMenuItem("Set Time Slice");
        private static JMenuItem exitSystemItem = new JMenuItem("Exit");
        private static JMenu helpMenu = new JMenu("Help");
        private static JMenuItem aboutItem = new JMenuItem("About");
    
        //设置优先级最高(即49)的队列的时间片大小默认值(单位:秒)
        public static double timeSlice = 0.5;
    
        //设置每个队列对应的时间片大小
        public static double PCBsQueuesTimeSlice[] = new double[50];
    
        //多级反馈队列
        public static PCBsQueue[] PCBsQueues = new PCBsQueue[50];
    
        //记录已经使用的pid
        public static int[] pidsUsed = new int[101];
    
        //当前内存中的进程数
        public static int currentPCBsNum = 0;
    
        //内存中能够容纳的最大进程数(这里取决于可分配的pid的个数)
        public static final int PCBS_MAX_NUM = 100;
    
        //是否停止调度
        public static boolean isStopScheduling;
    
        //很短的main函数
        public static void main(String[] args)
        {
            new MFQSimulation().initWindow();
        }
    
    
    
        //执行窗口初始化
        public void initWindow()
        {
            //设置窗口风格为Windows风格
            setWindowsStyle();
    
            //创建菜单栏
            processSettingsMenu.add(createProcessItem);
            processSettingsMenu.addSeparator();
            processSettingsMenu.add(startMFQItem);
            processSettingsMenu.addSeparator();
            processSettingsMenu.add(stopMFQItem);
            processSettingsMenu.addSeparator();
            processSettingsMenu.add(setTimeSliceItem);
            processSettingsMenu.addSeparator();
            processSettingsMenu.add(exitSystemItem);
    
            helpMenu.add(aboutItem);
    
            menuBar.add(processSettingsMenu);
            menuBar.add(helpMenu);
    
            frame.setJMenuBar(menuBar);
    
            initMemory();
    
            panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    
            frame.setContentPane(scrollPane);
            frame.setSize(800, 700);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
    
    
            //为控件绑定监听器
            setComponentsListeners();
        }
    
        //设置Swing的控件显示风格为Windows风格
        public static void setWindowsStyle()
        {
            try
            {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            }
            catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e)
            {
                e.printStackTrace();
            }
    
        }
    
        //初始化相关内存参数
        public static void initMemory()
        {
            currentPCBsNum = 0;
    
            Arrays.fill(pidsUsed, 1, 101, 0);
    
            for(int i = 0; i < PCBsQueues.length; i++)
            {
                PCBsQueues[i] = new PCBsQueue(i);
            }
    
            for(int i = PCBsQueuesTimeSlice.length - 1; i >= 0; i--)
            {
                //队列优先级每降一级,时间片增加0.1秒
                PCBsQueuesTimeSlice[i] = timeSlice;
                timeSlice += 0.1;
            }
        }
    
        //给窗口中所有控件绑定监听器
        public static void setComponentsListeners()
        {
            createProcessItem.setAccelerator(KeyStroke.getKeyStroke('F', InputEvent.CTRL_MASK));
            createProcessItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    createProcess();
                }
            });
    
    
            startMFQItem.setAccelerator(KeyStroke.getKeyStroke('S', InputEvent.CTRL_MASK));
            startMFQItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    startMFQSimulation();
                }
            });
    
            stopMFQItem.setAccelerator(KeyStroke.getKeyStroke('P', InputEvent.CTRL_MASK));
            stopMFQItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    stopMFQSimulation();
                }
            });
    
            setTimeSliceItem.setAccelerator(KeyStroke.getKeyStroke('T', InputEvent.CTRL_MASK));
            setTimeSliceItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    setTimeSlice();
                }
            });
    
    
            exitSystemItem.setAccelerator(KeyStroke.getKeyStroke('E', InputEvent.CTRL_MASK));
            exitSystemItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    System.exit(0);
                }
            });
    
            aboutItem.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.CTRL_MASK));
            aboutItem.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    JOptionPane.showMessageDialog(frame, "Multilevel feedback queue simulation application (1.0 version)\n\nCopyright © 2018, 余梓权, All Rights Reserved.");
                }
            });
    
        }
    
        //创建新进程
        public static void createProcess()
        {
            if(currentPCBsNum == PCBS_MAX_NUM)
            {
                JOptionPane.showMessageDialog(frame,"The current memory space is full and cannot create a new process!");
            }
            else
            {
                currentPCBsNum++;
    
                int randomPid = 1 + (int)(Math.random() * ((100 - 1) + 1));
    
                while(pidsUsed[randomPid] == 1)
                {
                    randomPid = 1 + (int)(Math.random() * ((100 - 1) + 1));
                }
    
                pidsUsed[randomPid] = 1;
    
                int randomPriority = 0 + (int)(Math.random() * ((49 - 0) + 1));
                int randomLife = 1 + (int)(Math.random() * ((5 - 1) + 1));
    
                PCB pcb = new PCB(randomPid, "Ready", randomPriority, randomLife);
    
                LinkedList<PCB> queue = PCBsQueues[randomPriority].getQueue();
                queue.offer(pcb);
                PCBsQueues[randomPriority].setQueue(queue);
    
                showPCBQueues(PCBsQueues);
            }
        }
    
        //开始调度
        public static void startMFQSimulation()
        {
            isStopScheduling = false;
    
            //更新界面操作必须借助多线程来实现
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    //当前内存中还留有进程未执行
                    while(currentPCBsNum!=0 && !isStopScheduling)
                    {
                        for(int i = PCBsQueues.length - 1; i >= 0; i--)
                        {
                            LinkedList<PCB> queue = PCBsQueues[i].getQueue();
    
                            if (queue.size() > 0)
                            {
                                //读取该队列首个PCB
                                PCB pcb = queue.element();
                                pcb.setStatus("Running");
                                showPCBQueues(PCBsQueues);
    
                                int pid = pcb.getPid();
                                int priority = pcb.getPriority();
                                int life = pcb.getLife();
                                priority = priority / 2;
                                life = life - 1;
    
                                //通过延时一个时间片来模拟该进程的执行
                                try
                                {
                                    Thread.sleep((int)(PCBsQueuesTimeSlice[priority] * 1000));
                                }
                                catch (InterruptedException e)
                                {
                                    e.printStackTrace();
                                }
    
                                //若该进程执行完成
                                if(life == 0)
                                {
                                    //移除该队列的首个PCB
                                    queue.poll();
                                    pidsUsed[pid] = 0;
                                    currentPCBsNum--;
                                }
                                //若该进程还未执行完成,则改变其PCB的相关参数,并插入其优先级所对应的队列尾部
                                else
                                {
                                    //移除该队列的首个PCB
                                    queue.poll();
    
                                    pcb.setPriority(priority);
                                    pcb.setLife(life);
                                    pcb.setStatus("Ready");
                                    LinkedList<PCB> nextQueue = PCBsQueues[priority].getQueue();
                                    nextQueue.offer(pcb);
                                    PCBsQueues[priority].setQueue(nextQueue);
                                }
    
                                break;
                            }
                        }
                    }
    
                    initMemory();
                    showPCBQueues(PCBsQueues);
                    //所有进程均执行完成,进程调度完成
                    JOptionPane.showMessageDialog(frame, "Process scheduling over!");
                }
            }).start();
    
        }
    
        //强制结束进程调度
        public static void stopMFQSimulation()
        {
            isStopScheduling = true;
            initMemory();
        }
    
        //设置时间片大小
        public static void setTimeSlice()
        {
            String inputMsg = JOptionPane.showInputDialog(frame, "Please input your time slice(seconds):", 0.5);
    
            double timeSliceInput = Double.parseDouble(inputMsg);
    
            while(timeSliceInput <= 0)
            {
                JOptionPane.showMessageDialog(frame, "Time  Slice is illegal, Please set time slice again!");
                inputMsg = JOptionPane.showInputDialog(frame, "Please input your time slice(seconds):", "Set Time Slice", JOptionPane.PLAIN_MESSAGE);
                timeSliceInput = Integer.parseInt(inputMsg);
            }
    
            timeSlice = timeSliceInput;
        }
    
        //显示内存中的多级反馈队列
        public static void showPCBQueues(PCBsQueue[] PCBsQueues)
        {
            int queueLocationY = 0;
            JPanel queuesPanel = new JPanel();
    
            for(int i = PCBsQueues.length - 1; i >= 0; i--)
            {
                LinkedList<PCB> queue = PCBsQueues[i].getQueue();
    
                if (queue.size() > 0)
                {
                    //创建一个PCB队列
                    JPanel PCBsQueue = new JPanel();
                    // PCBsQueue.setBorder(BorderFactory.createLineBorder(Color.BLACK));
                    PCBsQueue.setLayout(new FlowLayout(FlowLayout.LEFT));
                    PCBsQueue.setBounds(0, queueLocationY, 800, 700);
    
                    queueLocationY += 50;
    
                    //创建队列前面的优先级提示块
                    JLabel PCBsQueuePriorityLabel = new JLabel("Priority of queue: " + String.valueOf(i));
                    PCBsQueuePriorityLabel.setOpaque(true);
                    PCBsQueuePriorityLabel.setBackground(Color.RED);
                    PCBsQueuePriorityLabel.setForeground(Color.YELLOW);
    
                    JPanel PCBsQueuePriorityBlock = new JPanel();
                    PCBsQueuePriorityBlock.add(PCBsQueuePriorityLabel);
    
                    PCBsQueue.add(PCBsQueuePriorityBlock);
    
                    for (PCB pcb : queue)
                    {
    
                        //JLabel默认情况下是透明的所以直接设置背景颜色是无法显示的,必须将其设置为不透明才能显示背景
    
                        //设置pid标签
                        JLabel pidLabel = new JLabel("Pid: " + String.valueOf(pcb.getPid()));
                        pidLabel.setOpaque(true);
                        pidLabel.setBackground(Color.GREEN);
                        pidLabel.setForeground(Color.RED);
                        pidLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    
                        //设置status标签
                        JLabel statusLabel = new JLabel("Status: " + pcb.getStatus());
                        statusLabel.setOpaque(true);
                        statusLabel.setBackground(Color.GREEN);
                        statusLabel.setForeground(Color.RED);
                        statusLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    
                        //设置priority标签
                        JLabel priorityLabel = new JLabel("Priority: " + String.valueOf(pcb.getPriority()));
                        priorityLabel.setOpaque(true);
                        priorityLabel.setBackground(Color.GREEN);
                        priorityLabel.setForeground(Color.RED);
                        priorityLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    
                        //设置life标签
                        JLabel lifeLabel = new JLabel("Life: " + String.valueOf(pcb.getLife()));
                        lifeLabel.setOpaque(true);
                        lifeLabel.setBackground(Color.GREEN);
                        lifeLabel.setForeground(Color.RED);
                        lifeLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    
                        //绘制一个PCB
                        JPanel PCBPanel = new JPanel();
                        PCBPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
                        PCBPanel.setBackground(Color.BLUE);
                        PCBPanel.add(pidLabel);
                        PCBPanel.add(statusLabel);
                        PCBPanel.add(priorityLabel);
                        PCBPanel.add(lifeLabel);
    
                        //将PCB加入队列
                        PCBsQueue.add(new DrawLinePanel());
                        PCBsQueue.add(PCBPanel);
                    }
    
                    queuesPanel.add(PCBsQueue);
                }
            }
    
    
            //设置queuesPanel中的所有PCB队列(PCBsQueue组件)按垂直方向排列
            BoxLayout boxLayout = new BoxLayout(queuesPanel, BoxLayout.Y_AXIS);
            queuesPanel.setLayout(boxLayout);
    
            queuesPanel.setSize(800, 700);
    
            panel.setLayout(new FlowLayout(FlowLayout.LEFT));
            panel.removeAll();
            panel.add(queuesPanel);
            panel.updateUI();
            panel.repaint();
        }
    
    }
    
    
    
    //绘制直线类
    class DrawLinePanel extends JPanel
    {
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.drawLine(0, this.getSize().height / 2, this.getSize().width, this.getSize().height/2);
    
        }
    
    }
    



    五、相关说明

    鉴于上述代码都添加了必要的注释,故这里也不细究代码的细节问题。

    • 此次进程调度的模拟实现的关键在于MFQSimulation这个类,GUI的实现关键在于该类中的showPCBQueues静态方法。
    • 实现实时更新界面不能使用主线程(默认当前线程即为主线程)来更新,而应借助多线程的技术来实现更新操作。
    • 鉴于Swing默认的界面显示风格比较丑,所以使用了Windows风格来显示。
    • 设置组件垂直排列,可借助BoxLayout。
    • 关于向Panel中动态添加组件并显示的问题:

    eg:

    
    JPanel panel = new JPanel();
    ......
    
    监听器方法
    {
        panel.removeAll();
    
        JButton button = new JButton("Hello");
        panel.add(button);
    
        panel.updateUI();
        panel.repaint();
    }

    当触发该控件,以上代码成功添加并在JPanel中显示了一个按钮。


    但是,如果向JPanel中添加“没有布局”的JPanel(这里假设为panel已经被你设置panel.setLayout(null),因为你想要使用绝对布局方式),则最终只是显示一个小黑点,没有成功显示你所添加的panel。


    综上,如果要为JPanel添加JPanel,被添加的JPanel一定要带有相应的布局管理器!


    六、源代码和Jar包下载

    顺便附上项目源码,支持开源精神,欢迎star、fork:
    https://github.com/Yuziquan/MultilevelFeedbackQueueSimulation


    (希望可以帮到有需要的人~~)

    展开全文
  • 参考先来先服务算法,尝试实现其他四种调度算法:短作业优先、高响应比、时间片轮转、多级反馈队列。要求至少实现一种算法。 除了多级反馈队列,其他算法采用非抢占调度 短作业优先算法使用例题一数据或程序内置...

    ​​​​​​这是操作系统课程的一次综合实验,模拟各种调度算法。

    参考先来先服务算法,尝试实现其他四种调度算法:短作业优先、高响应比、时间片轮转、多级反馈队列。要求至少实现一种算法。

    1. 除了多级反馈队列,其他算法采用非抢占调度
    2. 短作业优先算法使用例题一数据或程序内置数据,要求运行结果给出调度顺序、完成时间、周转时间、带权周转时间
    3. 高响应比算法使用例题二的数据,要求运行结果给出调度顺序、完成时间、周转时间、带权周转时间
    4. 时间片轮转算法可以使用程序内置数据,要求运行结果给出每个时间片是被哪个进程使用,每个进程完成时,要修改状态并输出提示。
    5. 多级反馈队列算法使用例题三的数据,要求运行结果给出正确的进程调度顺序和过程描述。

    例题一:在单处理机环境下,对4个作业Job1、Job2、Job3、Job4进行非抢占式调度,它们的到达时间均为1,所需运行时间分别为9、16、3、11。

    例题二:在单处理机环境下,对4个进程P1、P2、P3、P 4进行非抢占式调度,它们的到达时间分别为10、12、14、16,运行时间分别为8、12、4、6。

    例题三:某一操作系统中对进程调度采用级反馈队列调度算法。现设定采用三级反馈队列调度算法三个队列分别为I、II、III,对应时间片为248。现有四个进程A、B、C、D,到达时刻分别为0、5712,执行时间分别为74139。请写出整个进程调度过程。

     

    编写其他调度算法:

    1、首先我对PCB结构加了两个成员:(最后两个)

    struct pcb{
    
        int id;
    
        char name[10];
    
        int time_start; //到达时间
    
        int time_need; //运行时间
    
        int time_left; //剩余时间
    
        int time_used;
    
        /* time_need = time_left + time_used */
    
    char state;
    
    /* T:(TAKEIN) */
    
    /* R:(RUN) */
    
    /* W: (WAIT) */
    
    /* F : (FINIISH) */
    
        int startTime; //开始时间(用于短作业优先算法)
    
        int leftTime; //在该时间片下的剩余时间(用于多级反馈队列算法)
    
    };

     

    • 编写短作业优先算法

    (1)短作业优先的思想是优先执行运行时间短的进程,但不抢占

    (2)不管什么调度算法都要先按照到达时间进程排序:

    /* 按到达时间排序 */
    
    void sortByArriveTime(PCB* pcb)
    
    {
    
        for(int i = 0; i < num1; i++)
    
        {
    
            /* 最小的到达时间 */
    
            int min = pcb[i].time_start;
    
            /* 最小到达时间的进程下标 */
    
            int minIndex = i;
    
            for(int j = i + 1; j < num1; j++)
    
            {
    
                if(pcb[j].time_start < min)
    
                {
    
                    min = pcb[j].time_start;
    
                    minIndex = j;
    
                }
    
            }
    
    
    
            PCB temp = pcb[i];
    
            pcb[i] = pcb[minIndex];
    
            pcb[minIndex] = temp;
    
        }
    
    }

    (3)全局变量,贯穿整个调度算法,根据当前时间来判断是否有新的进程到达,根据当前完成进程个数来判断循环是否结束

    /* 当前时间 */
    
    int currentTime = 0;
    
    /* 已经完成的进程个数 */
    
    int finishNumber = 0;
    
    

    (4)由于要保证短作业优先,所以在一个进程结束后要找到等待队列中的最短运行时间的进程

    /* 根据当前时间修改state状态 */
    
    void statusWait(PCB* pcb)
    
    {
    
        for(int i = 0; i < num1; i++)
    
        {
    
            /* printf("pcb[%d].state = %c\n", i, pcb[i].state); */
    
            if(currentTime >= pcb[i].time_start && pcb[i].state == 'T')
    
            {
    
                pcb[i].state = 'W';
    
            }
    
        }
    
    }
    
    
    
    /* 定义一个比较大的数,各个进程的time_need都比他小 */
    
    #define MAX 1000
    
    
    
    /* 确定当前时间wait进程中最短进程的下标 */
    
    int shortIndex(PCB* pcb)
    
    {
    
        int min = MAX, temp = -1;
    
        statusWait(pcb);
    
        for(int i = 0; i < num1; i++)
    
        {
    
            if(pcb[i].state == 'W')
    
            {
    
                if(pcb[i].time_need <= min)
    
                {
    
                    min = pcb[i].time_need;
    
                    temp = i;
    
                }
    
            }
    
        }
    
        return temp;
    
    }
    
    
    1. 核心程序
    void runProcess(PCB* pcb)
    
    {
    
        int index = shortIndex(pcb);
    
        if(index != -1)
    
        {
    
            pcb[index].startTime = currentTime;
    
            pcb[index].state = 'R';
    
            int endTime = currentTime + pcb[index].time_need;
    
            while(1)
    
            {
    
                statusWait(pcb);
    
                if(currentTime == endTime)
    
                {
    
                    /* 相等即说明该进程运行结束 */
    
                    pcb[index].state = 'F';
    
                    finishNumber++;
    
                    break;
    
                }
    
                else
    
                    currentTime++;
    
            }
    
        }
    
    }
    
    
    
    void SJF()
    
    {
    
        sortByArriveTime(pcbdata);
    
        /* 第一个进程的到达时间 */
    
        int firstArriveTime = pcbdata[0].time_start;
    
    
    
        for(; finishNumber != num; currentTime++)
    
        {
    
            if(firstArriveTime >= currentTime)
    
            {
    
                continue;
    
            }
    
            else
    
            {
    
                currentTime--;
    
                runProcess(pcbdata);
    
            }
    
        }
    
    
    
        /* 下面的代码与先来先服务算法基本相同,只是是按照开始时间startTime来排序 */
    
        int i, j, temp;
    
        double k;
    
        for(i = 0; i < num; i++)
    
        {
    
            order[i] = pcbdata[i].startTime;
    
            ready[i] = i;
    
        }
    
        /* 用冒泡排序排序到达时间 */
    
        for(i = 0; i < num; i++)
    
            for(j = i + 1; j < num; j++)
    
            {
    
                if(order[i] > order[j])
    
                {
    
                    temp = order[i];
    
                    order[i] = order[j];
    
                    order[j] = temp;
    
                    temp = ready[i];
    
                    ready[i] = ready[j];
    
                    ready[j] = temp;
    
                }
    
            }
    
    
    
        printf("---短作业优先算法调度:非抢占,无时间片---\n");
    
        /* 记录第一个到达的时间 */
    
        temp = pcbdata[ready[0]].time_start;
    
        for(i = 0; i < num; i++)
    
        {
    
            printf("第%d个进程-- %s, ", i+1, pcbdata[ready[i]].name);
    
            printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                    pcbdata[ready[i]].time_start,
    
                    pcbdata[ready[i]].time_need);
    
            printf("本进程正在运行-----------");
    
            _sleep(1);
    
            printf("运行完毕\n");
    
            temp += pcbdata[ready[i]].time_need;
    
            j = temp - pcbdata[ready[i]].time_start;
    
            k = (float)j / pcbdata[ready[i]].time_need;
    
            printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
        }
    
        printf("-------所有进程调度完毕--------\n");
    
    }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    短作业优先算法运行结果:

     

     

     

     

     

     

     

     

     

     

     

     

     

    4、编写高响应比算法

      高响应比的算法也比较简单,只是需要在每次调用完一个进程后挑选在等待队列中优先级最高的进程


     

    /* --------------------------高响应比优先算法--------------------------*/
    
    void HRF()
    
    {
    
        int currentTime2 = 0;
    
        int finishNumber2 = 0;
    
        float priority[4];
    
    
    
        sortByArriveTime(pcbdata);
    
        int j = 0;
    
        double k;
    
        int temp = pcbdata[0].time_start;
    
    
    
        for(; finishNumber2 != num; currentTime2++)
    
        {
    
            float maxPriority = 0.0;
    
            int indexPriority = 0;
    
            if(currentTime2 < pcbdata[0].time_start)
    
            {
    
                continue;
    
            }
    
            else
    
            {
    
                /* 找出优先级最大的进程下标indexPriority */
    
                for(int i = 0; i < num; i++)
    
                {
    
                    /* 在没完成的进程中进行优先级计算 */
    
                    if(pcbdata[i].state != 'F')
    
                    {
    
                        int waitTime = currentTime2 - pcbdata[i].time_start;
    
                        priority[i] = (waitTime + pcbdata[i].time_need) * 1.0 / pcbdata[i].time_need;
    
                        if(priority[i] > maxPriority)
    
                        {
    
                            maxPriority = priority[i];
    
                            indexPriority = i;
    
                        }
    
                    }
    
                }
    
    
    
                /* 记录该进程的开始时间 */
    
                pcbdata[indexPriority].startTime = currentTime2;
    
                pcbdata[indexPriority].state = 'R';
    
                /* 计算该进程的结束时间 */
    
                int endTime = pcbdata[indexPriority].startTime + pcbdata[indexPriority].time_need;
    
                while(1)
    
                {
    
                    if(currentTime2 == endTime)
    
                    {
    
                        pcbdata[indexPriority].state = 'F';
    
                        finishNumber2++;
    
    
    
                        /* 与前面的基本一样 */
    
                        printf("第%d个进程-- %s, ", indexPriority+1, pcbdata[indexPriority].name);
    
                        printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                                pcbdata[indexPriority].time_start,
    
                                pcbdata[indexPriority].time_need);
    
                        printf("本进程正在运行-----------");
    
                        _sleep(1);
    
                        printf("运行完毕\n");
    
                        /* temp += pcbdata[indexPriority].time_need; */
    
                        temp = currentTime2;
    
                        j = temp - pcbdata[indexPriority].time_start;
    
                        k = (double)j / pcbdata[indexPriority].time_need;
    
                        printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
    
    
                        currentTime2--;
    
                        break;
    
                    }
    
                    else
    
                    {
    
                        currentTime2++;
    
                    }
    
                }
    
            }
    
        }
    
    
    
        currentTime2 = 0;
    
        finishNumber2 = 0;
    
    }
    
    
    • 编写按照先来先服务并使用时间片轮转算法

    时间片轮转运用到了队列(在后面的多级反馈队列算法也有用到),所以我实现了一个先入先出的队列(Queue.h,参考数据结构C语言描述),用于实现等待队列

    Queue.h:
    
    #ifndef __QUEUE_H
    
    #define __QUEUE_H
    
    
    
    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <error.h>
    
    
    
    struct queuerecord;
    
    typedef struct queuerecord *queue;
    
    struct queuerecord{
    
        int capacity;
    
        int front;
    
        int rear;
    
        int size;
    
        int *array;
    
    };
    
    
    
    int isempty(queue q);
    
    int isfull(queue q);
    
    queue createqueue(int max);
    
    void disposequeue(queue q);
    
    void makeempty(queue q);
    
    void enqueue(int x, queue q);
    
    int front(queue q);
    
    void dequeue(queue q);
    
    int frontanddequeue(queue q);
    
    
    
    queue createqueue(int x){
    
        queue q;
    
        q = malloc(sizeof(struct queuerecord));
    
        if(q == NULL){
    
            printf("out of space!!\n");
    
        }
    
    
    
        q->array = malloc(sizeof(int) * x);
    
        if(q->array == NULL){
    
            printf("out of space!\n");
    
        }
    
        q->capacity = x;
    
        makeempty(q);
    
        return q;
    
    }
    
    
    
    void
    
    disposequeue(queue q){
    
        if(q != NULL){
    
            free(q->array);
    
            free(q);
    
        }
    
    }
    
    
    
    int
    
    isempty(queue q){
    
        return q->size == 0;
    
    }
    
    
    
    void
    
    makeempty(queue q){
    
        q->size = 0;
    
        q->front = 1;
    
        q->rear = 0;
    
    }
    
    
    
    int
    
    isfull(queue q){
    
        return q->size == q->capacity;
    
    }
    
    
    
    static int
    
    succ(int value, queue q){
    
        if(++value == q->capacity){
    
            value = 0;
    
        }
    
        return value;
    
    }
    
    
    
    void
    
    enqueue(int x, queue q){
    
        if(isfull(q)){
    
            /* printf("full queue\n"); */
    
            perror("full queue\n");
    
        } else {
    
            q->size++;
    
            q->rear = succ(q->rear, q);
    
            q->array[q->rear] = x;
    
        }
    
    }
    
    
    
    void dequeue(queue q){
    
        if(isempty(q)){
    
            /* printf("empty queue\n"); */
    
            perror("empty queue\n");
    
        } else{
    
            q->size--;
    
            q->front = succ(q->front, q);
    
        }
    
    }
    
    
    
    int frontanddequeue(queue q){
    
        int temp = -1;          //元素中不能有-1这个值
    
        if(!isempty(q)){
    
            temp = q->array[q->front];
    
            dequeue(q);
    
        } else{
    
            perror("empty queue\n");
    
            /* printf("empty queue\n"); */
    
        }
    
        return temp;
    
    }
    
    #endif
    
    /* -------------------------按照先来先服务并使用时间片轮转------------------------- */
    
    
    
    void Timeslice()
    
    {
    
        sortByArriveTime(pcbdata);
    
    
    
        int currentTime3 = 0;
    
        int finishNumber3 = 0;
    
        int temp, j, i = 0, count;
    
        float k;
    
    
    
        queue q = createqueue(num);
    
    
    
        for(; finishNumber3 != num;)
    
        {
    
            /* 还没到该进程的到达时间 */
    
            if(currentTime3 < pcbdata[i].time_start)
    
            {
    
                currentTime3++;
    
                continue;
    
            }
    
            else
    
            {
    
                /* 让那些在其它进程运行期间到达的进程入队 */
    
                for(int t = 0; t < num; t++)
    
                {
    
                    if(currentTime3 >= pcbdata[t].time_start && pcbdata[t].state == 'T')
    
                    {
    
                        /* 入队 */
    
                        enqueue(t, q);
    
                        pcbdata[t].state = 'W';
    
                    }
    
                }
    
    
    
                /* 出队并且取值 */
    
                i = frontanddequeue(q);
    
                printf("%s\n", pcbdata[i].name);
    
    
    
                for(count = 0; count < time_unit; count++)
    
                {
    
                    if(pcbdata[i].time_left != 0)
    
                    {
    
                        currentTime3++;
    
                        pcbdata[i].state = 'R';
    
                        pcbdata[i].time_used++;
    
                        pcbdata[i].time_left--;
    
                    }
    
    
    
    
    
                    /* 在经过一个单位时间后如果进程已经完成了 */
    
                    if(pcbdata[i].time_left  == 0)
    
                    {
    
                        pcbdata[i].state = 'F';
    
                        finishNumber3++;
    
    
    
                        printf("第%d个进程-- %s, ", i+1, pcbdata[i].name);
    
                        printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                                pcbdata[i].time_start,
    
                                pcbdata[i].time_need);
    
                        printf("本进程正在运行-----------");
    
                        _sleep(1);
    
                        printf("运行完毕\n");
    
                        temp = currentTime3;
    
                        j = temp - pcbdata[i].time_start;
    
                        k = (float)j / pcbdata[i].time_need;
    
                        printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
    
    
                        break;
    
                    }
    
    
    
                }
    
    
    
                for(int t = 0; t < num; t++)
    
                {
    
                    if(currentTime3 >= pcbdata[t].time_start && pcbdata[t].state == 'T')
    
                    {
    
                        /* 入队 */
    
                        enqueue(t, q);
    
                        pcbdata[t].state = 'W';
    
                    }
    
                }
    
    
    
                if(pcbdata[i].state == 'R')
    
                {
    
                    enqueue(i, q);
    
                    pcbdata[i].state = 'W';
    
                }
    
            }
    
        }
    
    }
    
    
    1. 编写多级反馈队列调度算法

    多级反馈队列算法基于时间片算法可以比较简单的实现,不同的是要维护三个队列,且每个队列优先级不同

    • 全局变量
    int currentTime4 = 0;
    
    int finishNumber4 = 0;
    
    
    
    int time_unit1 = 4;
    
    int time_unit2 = 8;
    
    int time_unit3 = 16;

     

    • 挑选进程
    static int selectProcess(queue q1, queue q2, queue q3)
    
    {
    
        /* 优先从高优先级的队列取出进程 */
    
        if(!isempty(q1))
    
        {
    
            return frontanddequeue(q1);
    
        }
    
        else if(!isempty(q2))
    
        {
    
            return frontanddequeue(q2);
    
        }
    
        else if(!isempty(q3))
    
        {
    
            return frontanddequeue(q3);
    
    }
    
    return -1; //无意义,只是为了消除警告
    
    }
    
    
    • 核心函数
    /* --------------------------多级反馈调度队列,抢占式调度-------------------------- */
    
    void MRLA()
    
    {
    
        /* 创建三个队列 */
    
        queue q1 = createqueue(num);
    
        queue q2 = createqueue(num);
    
        queue q3 = createqueue(num);
    
        int temp, j, count;
    
        double k;
    
        sortByArriveTime(pcbdata);
    
        int i = 0;
    
    
    
        for(; finishNumber4 != num; )
    
        {
    
            if(currentTime4 < pcbdata[i].time_start)
    
            {
    
                currentTime4++;
    
                continue;
    
            }
    
            else
    
            {
    
                /* 让那些在其它进程运行期间到达的进程入队 */
    
                for(int t = 0; t < num; t++)
    
                {
    
                    if(currentTime4 >= pcbdata[t].time_start && pcbdata[t].state == 'T')
    
                    {
    
                        /* 入队 */
    
                        enqueue(t, q1);
    
                        pcbdata[t].state = 'W';
    
                    }
    
                }
    
    
    
                int q1Flag = 0;
    
                int q2Flag = 0;
    
                int q3Flag = 0;
    
                int tmp1 = q1->size;
    
                int tmp2 = q2->size;
    
                int tmp3 = q3->size;
    
                i = selectProcess(q1, q2, q3);
    
                printf("%s\n", pcbdata[i].name);
    
                /* 用来判断是从哪个队列取的进程 */
    
                if(tmp1 > q1->size)
    
                    q1Flag = 1;
    
                else if(tmp2 > q2->size)
    
                    q2Flag = 1;
    
                else if(tmp3 > q3->size)
    
                    q3Flag = 1;
    
    
    
                if(q1Flag)
    
                {
    
                    /* 执行队列一的时间片长度 */
    
                    for(count = 0; count < time_unit1; count++)
    
                    {
    
                        if(pcbdata[i].time_left != 0)
    
                        {
    
                            currentTime4++;
    
                            pcbdata[i].state = 'R';
    
                            pcbdata[i].time_used++;
    
                            pcbdata[i].time_left--;
    
                        }
    
    
    
                        if(pcbdata[i].time_left  == 0)
    
                        {
    
                            pcbdata[i].state = 'F';
    
                            finishNumber4++;
    
    
    
                            printf("第%d个进程-- %s, ", i+1, pcbdata[i].name);
    
                            printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                                    pcbdata[i].time_start,
    
                                    pcbdata[i].time_need);
    
                            printf("本进程正在运行-----------");
    
                            _sleep(1);
    
                            printf("运行完毕\n");
    
                            temp = currentTime4;
    
                            j = temp - pcbdata[i].time_start;
    
                            k = (double)j / pcbdata[i].time_need;
    
                            printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
                            break;
    
                        }
    
                    }
    
                    /* 完成第一个队列的时间片仍未完成,然后添加到第二个队列 */
    
                    if(pcbdata[i].state == 'R')
    
                    {
    
                        enqueue(i, q2);
    
                        pcbdata[i].state = 'W';
    
                    }
    
                }
    
                else if(q2Flag)
    
                {
    
                    if(pcbdata[i].leftTime == 0)
    
                        pcbdata[i].leftTime = time_unit2;
    
                    for(count = 0; count < pcbdata[i].leftTime; count++)
    
                    {
    
                        if(pcbdata[i].time_left != 0)
    
                        {
    
                            currentTime4++;
    
                            pcbdata[i].state = 'R';
    
                            pcbdata[i].time_used++;
    
                            pcbdata[i].time_left--;
    
                        }
    
    
    
    
    
                        if(pcbdata[i].time_left  == 0)
    
                        {
    
                            pcbdata[i].state = 'F';
    
                            finishNumber4++;
    
    
    
                            printf("第%d个进程-- %s, ", i+1, pcbdata[i].name);
    
                            printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                                    pcbdata[i].time_start,
    
                                    pcbdata[i].time_need);
    
                            printf("本进程正在运行-----------");
    
                            _sleep(1);
    
                            printf("运行完毕\n");
    
                            temp = currentTime4;
    
                            j = temp - pcbdata[i].time_start;
    
                            k = (double)j / pcbdata[i].time_need;
    
                            printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
                            break;
    
                        }
    
    
    
                        /* 每调用一个单位时间就判断是否第一级队列是否有进程抢占 */
    
                        for(int t = 0; t < num; t++)
    
                        {
    
                            if(currentTime4 >= pcbdata[t].time_start && pcbdata[t].state == 'T')
    
                            {
    
                                /* 入队 */
    
                                enqueue(t, q1);
    
                                pcbdata[t].state = 'W';
    
                            }
    
                        }
    
    
    
                        if(!isempty(q1))
    
                        {
    
                            /* 有第一队列的进程抢占 */
    
                            pcbdata[i].state = 'W';
    
                            /* 添加到队列末尾 */
    
                            enqueue(i, q2);
    
                            pcbdata[i].leftTime = pcbdata[i].leftTime - count - 1;
    
                            break;
    
                        }
    
                    }
    
                    if(pcbdata[i].state == 'R')
    
                    {
    
                        enqueue(i, q3);
    
                        pcbdata[i].state = 'W';
    
                    }
    
                }
    
                else if(q3Flag)
    
                {
    
                    for(count = 0; count < time_unit3; count++)
    
                    {
    
                        if(pcbdata[i].time_left != 0)
    
                        {
    
                            currentTime4++;
    
                            pcbdata[i].state = 'R';
    
                            pcbdata[i].time_used++;
    
                            pcbdata[i].time_left--;
    
                        }
    
    
    
                        /* 在经过一个单位时间后如果进程已经完成了 */
    
                        if(pcbdata[i].time_left  == 0)
    
                        {
    
                            pcbdata[i].state = 'F';
    
                            finishNumber4++;
    
    
    
                            printf("第%d个进程-- %s, ", i+1, pcbdata[i].name);
    
                            printf("到达时间 -- %d, 服务时间 -- %d\n",
    
                                    pcbdata[i].time_start,
    
                                    pcbdata[i].time_need);
    
                            printf("本进程正在运行-----------");
    
                            _sleep(1);
    
                            printf("运行完毕\n");
    
                            temp = currentTime4;
    
                            j = temp - pcbdata[i].time_start;
    
                            k = (double)j / pcbdata[i].time_need;
    
                            printf("完成时间 -- %d,周转时间 -- %d, 带权周转时间 -- %.1f\n", temp, j, k);
    
                            break;
    
                        }
    
    
    
                        for(int t = 0; t < num; t++)
    
                        {
    
                            if(currentTime4 >= pcbdata[t].time_start && pcbdata[t].state == 'T')
    
                            {
    
                                /* 入队 */
    
                                enqueue(t, q1);
    
                                pcbdata[t].state = 'W';
    
                            }
    
                        }
    
    
    
                        if(!isempty(q1))
    
                        {
    
                            pcbdata[i].state = 'W';
    
                            enqueue(i, q3);
    
                            pcbdata[i].leftTime = pcbdata[i].leftTime - count - 1;
    
                            break;
    
                        }
    
    
    
                        if(!isempty(q2))
    
                        {
    
                            pcbdata[i].state = 'W';
    
                            enqueue(i, q3);
    
                            pcbdata[i].leftTime = pcbdata[i].leftTime - count - 1;
    
                            break;
    
                        }
    
                    }
    
                }
    
            }
    
        }
    
    }
    
    

     

    展开全文
  • 进程调度算法模拟

    2018-02-05 15:36:26
    主线程创建20个子线程,分别实现FCFS调度、SJF调度、RR调度、优先级调度和多级队列调度,并且计算每个调度的平均等待时间。(其中优先级调度和多级队列调度为选做)。 对于每个子线程,在其运行期间,输出其占用的...
  • 很详细,五种算法 ,先来先服务,短作业优先,最高响应比,时间片轮转,多级反馈队列,进程控制,挂起,等等
  • 编程实现四种调度算法: (1) 先来先服务算法 (2) 短作业优先算法 (3) 优先权算法 (4) 基于时间片的多级反馈队列算法 基本要求 (1) 通过若干个实例实现各种算法的优劣性对比; (2) 结果要求可视化展示
  • 大数据实时计算及可视化相关组件介绍 文章目录大数据实时计算及可视化相关组件介绍1.实时数据平台架构2 日志数据实时采集2.1 Apache Flume原理简介2.1.1 Agent结构2.1.2 基本概念(Source、Channel、Sink)2.1.3 Flume...

    大数据实时计算及可视化相关组件介绍

    1.实时数据平台架构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KHp2HTV8-1591611234730)(实时数据采集、分析及可视化.assets/实时数据平台架构.png)]

    大数据实时计算平台的支撑技术主要包含7个方面:

    • 日志数据实时采集:Flume、Fluentd、Logstash、Scribe等

    • 消息中间件:Kafka、RabbitMQ、Active MQ

    • 实时数据流计算框架:Spark Streaming、Flink、Storm

    • 数据实时存储:列族数据库Hbase、缓存数据库

    • 数据持久化:Mysql、Hbase

    • Web服务:将数据推送到前端

    • 可视化展示(实时数据应用,实时大屏):DataV(阿里云)、Echarts组件等。

    实时计算的典型特征:

    • **无边界:**实际的系统运行过程中,随着时间的推移,日志数据以及监控数据是源源不断的在产生的,就像河水一样不停的流过来。

    • **触发:**不同于Hadoop离线任务是定时调度触发,流计算任务的每次计算是由源头数据触发的。触发是流计算的一个非常重要的概念,在某些业务场景下,触发消息的逻辑比较复杂,对流计算挑战很大。

    • **延迟:**很显然,流计算必须能高效地、迅速地处理数据。不同于Hadoop任务至少以分组甚至小时计的处理延迟,流计算的延迟通常在秒甚至毫秒级,分组级别的延迟只有在特殊情况下才能被接受。

    • **历史数据:**Hadoop离线任务如果发现历史某天的数据有问题,通常很容易修复问题而且重运行任务,但是对于流计算任务基本不可能或代价非常大,以为首先实时流消息不会保存很久(一般几天),而且保存历史的完全现场基本不可能,所以实时流计算一般只能从问题发现的时刻修复数据,历史数据是无法通过流式方式来补的。

    2 日志数据实时采集

    任何完整的大数据平台,一般包括以下的几个过程:

    • 数据采集
    • 数据存储
    • 数据处理
    • 数据展现(可视化,报表和监控)

    大数据平台与数据采集

    其中,数据采集作为大数据系统体系的第一环节尤为重要。随着大数据越来越被重视,如何有效的正确的收集数据才能最大限度的避免信息孤岛,让数据产出更多的价值,这使得数据采集的挑战变的尤为突出,这其中包括:

    • 数据源多种多样

    • 数据量大,变化快

    • 如何保证数据采集的可靠性的性能

    • 如何避免重复数据

    • 如何保证数据的质量

    下面对当前可用的六款数据采集的产品进行介绍,进行深入了解

    2.1 Apache Flume原理简介

    Apache Flume 是开源日志系统。作为一个分布式、可靠性和高可用的海量日志聚合系统,它不仅支持在系统中定制各类数据发送方,用于收集数据;而且,也提供对数据进行简单处理,并写到各种数据接收方(可定制)的能力。Flume支持将集群外的日志文件采集并归档到HDFS、HBase、Kafka上,供上层应用对数据分析、清洗数据使用,如下图所示:

    在这里插入图片描述

    下面对Flume 的核心概念进行介绍

    • Client:Client生产数据,运行在一个独立的线程。
    • Event: 一个数据单元,消息头和消息体组成。(Events可以是日志记录、 avro 对象等。)
    • Flow: Event从源点到达目的点的迁移的抽象。
    • Agent: 一个独立的Flume进程,包含组件Source、 Channel、 Sink。(Agent使用JVM 运行Flume。每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks)
    • Source: 数据收集组件。(source从Client收集数据,传递给Channel)
    • Channel: 中转Event的一个临时存储,保存由Source组件传递过来的Event。(Channel连接 sources 和 sinks ,类似于一个队列。)
    • Sink: 从Channel中读取并移除Event, 将Event传递到FlowPipeline中的下一个Agent(如果有的话)(Sink从Channel收集数据,运行在一个独立线程)

    2.1.1 Agent结构

    Flume的数据流由事件(Event)贯穿始终。事件Flume的基本数据单位,它携带日志数据(字节数组形式)并且携带有头信息。Flume运行的核心是agent,Flume以agent为最小的独立运行单位。它是一个完整的数据收集工具,含有三个组件,分别是sourcechannelsink。这些Event由Agent外部的Source生成。通过这些组件,Event可以从一个地方流向另一个地方。
    Source捕获事件后会进行特定的格式化,然后Source会把事件推入(单个或多个)Channel中。可以把Channel看作是一个缓冲区,它将保存事件直到Sink处理完该事件。Sink负责持久化日志或者把事件推向另一个Source。一个 Flume 事件被定义为一个数据流单元。Flume agent 其实是一个 JVM 进程,该进程中包含完成任务所需要的各个组件,其中最核心的三个组件是 Source、Chanel 以及 Slink。
    Flume agent

    2.1.2 基本概念(Source、Channel、Sink)

    • Source

    Source负责接收events或通过特殊机制产生events,并将events批量放到一个或多个Channels(Source必须至少和一个channel关联)。有驱动和轮询两种类型的Source:

    • 1)驱动型Source:是外部主动发送数据给Flume,驱动Flume接收数据。
    • 2)轮询source:是FLume周期性主动去获取数据。

    source类型:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GavJl6Ic-1591611234746)(实时数据采集、分析及可视化.assets/Source类型.png)]

    • channel

    Channel位于SourceSink之间,Channel的作用类似队列,用于临时缓存进来的events,当Sink成功地将events发送到下一跳的channel或最终目的,events从Channel移除。

    不同的Channel提供的持久化水平也是不一样的:

    • Memory Channel:不会持久化。消息存放在内存中,提供高吞吐,但提供可靠性;可能丢失数据。
    • File Channel:对数据持久化;基于WAL(预写式日志Write-Ahaad Log)实现。但是配置较为麻烦,需要配置数据目录和checkpoint目录;不同的file channel均需要配置一个checkpoint目录。
    • JDBC Channel:基于嵌入式Database实现。内置derby数据库,对event进行了持久化,提供高可靠性;可以取代同样持久特性的file channel。

    Channels支持事物,提供较弱的顺序保证,可以连接任何数量的Source和Sink。

    • Sink
      Sink负责将events传输到下一跳或最终目的,成功完成后将events从channel移除。
      必须作用于一个确切的channel。
      Sink类型:

      在这里插入图片描述

    2.1.3 Flume关键特性

    • 支持多级级联和多路复制

      Flume支持将多个Flume级联起来,同时级联节点内部支持数据复制。

      这个场景主要应用于:收集FusionInsight集群外上的节点上的日志,并通过多个Flume节点,最终汇聚到集群当中。

    Flume级联

    • Flume级联消息压缩、加密

      Flume级联节点之间的数据传输支持压缩和加密,提升数据传输效率和安全性。

      在同一个Flume内部进行传输时,不需要加密,为进程内部的数据交换。

      Flume级联消息压缩、加密

    • Flume数据监控

      Source接收的数据量,Channel缓存的数据量,Sink写入的数据量,这些都可以通过Manager图形化界面呈现出来。

      Flume数据监控

    • Flume传输可靠性

      传输可靠性原理

      Flume在传输数据过程中,采用事物管理方式,保证数据传输过程中数据不会丢失,增强了数据传输的可靠性,同时缓存在channel中的数据如果采用了file channel,进程或者节点重启数据不会丢失。

    在这里插入图片描述

    • Flume传输过程中数据过滤
      Flume在传输数据过程中,可以见到的对数据简单过滤、清洗,可以去掉不关心的数据,同时如果需要对复杂的数据过滤,需要用户根据自己的数据特殊性,开发过滤插件,Flume支持第三方过滤插件调用
      在这里插入图片描述

    2.2 Fluentd

    Fluentd从各方面看都很像Flume,区别是使用Ruby开发,Footprint会小一些,但是也带来了跨平台的问题,并不能支持Windows平台。另外采用JSON统一数据/日志格式是它的另一个特点。相对于Flume,它配置也相对简单一些。

    2.3 Logstash

    Logstash是一个应用程序日志、事件的传输、处理、管理和搜索的平台。可以用它来统一对应用程序日志进行收集管理,提供了Web接口用于查询和统计。它是著名的开源数据栈ELK (ElasticSearch, Logstash, Kibana)中的那个L,几乎在大部分的情况下ELK作为一个栈是被同时使用的,只有当的数据系统使用ElasticSearch的情况下,logstash才是首选。

    2.4 Chukwa

    Apache Chukwa是apache旗下另一个开源的数据收集平台,上一次github的更新事7年前,该项目应该已经不活跃了。

    2.5 Scribe

    Scribe是Facebook开发的数据(日志)收集系统。它能够从各种日志源上收集日志,存储到一个中央存储系统(可以是NFS,分布式文件系统等)上,以便于进行集中统计分析处理。但是已经多年不维护。

    2.6 对比分析

    FlumeFluentd是两个被使用较多的产品。如果使用ElasticSearchLogstash也许是首选,因为ELK栈提供了很好的集成。ChukwaScribe由于项目的不活跃,不推荐使用。

    3 消息队列

    一发一存一消费,没有最好的消息队列中间件(简称消息中间件),只有最合适的消息中间件。
    消息队列常用的使用场景:

    • 非实时性:当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。主要解决了应用耦合、异步处理、流量削锋等问题。

    • 应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;(如:订单->库存)

    • 异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;(点对多场景,广播场景(注册发短信,发邮件)等等)

    • 限流削峰:应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;(根据服务承受度设置队列大小,超过了就返回活动结束了,咱们经常各大商城秒杀,心里还没有点B数吗)减少压力,避免服务挂掉。

    • 消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;(分工处理(各自对应相应的队列),灵活应用(收到就处理/定时处理))

    几种常用的消息队列比较
    消息队列
    比较有代表性的就是kafkarabbitMQ,下面分别对两者进行介绍:

    3.1 Kafka原理简介

    Kafka是由LinkedIn开发的一个高产出的分布式消息系统(A high-throughput distributed messaging system),采用Scala编写。它是一个高吞吐、分布式、基于发布订阅的消息系统,同时支持离线和在线日志处理。利用Kafka技术可以在廉价的PC Server上搭建起大规模消息系统。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark、Flink都支持与Kafka集成。

    在kafka中根据对消息保存时的Topic,将消息的发布者描述为producer,消息的订阅者描述为consumer,将中间的存储阵列称作broker(代理),这三者都通过Zookeeper进行协调。

    3.1.1 Kafka架构与功能

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S3969YXk-1591611234776)(C:\Users\lee\Desktop\实时数据采集、分析及可视化\Kafka图片\Kafka架构.png)]
    在这里插入图片描述
    基本概念:

    • Broker:Kafka集群包含一个或多个服务实例,这些服务实例被称为Broker。是Kafka当中具体处理数据的单元。Kafka支持Broker的水平扩展。一般Broker数据越多,集群的吞吐力就越强。
    • Topic:每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。
    • Partition:Kafka将Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件下存储这个Partition的所有消息。
    • Producer:负责发布消息到Kafka Broker。
    • Consumer:消息消费者,从Kafka Broker读取消息的客户端。
    • Consumer Group:每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name)。
    • ZooKeeper:Kafka与Zookeeper级联,通过Zookeeper管理级联配置,选举Leader。

    3.1.2 Kafka的特性

    • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作;
    • 可扩展性:kafka集群支持热扩展;
    • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失;
    • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败);
    • 高并发:支持数千个客户端同时读写;
    • 支持实时在线处理和离线处理:可以使用Storm、Spark、Flink等实时流处理系统对消息进行实时进行处理,同时还可以使用Hadoop这种批处理系统进行离线处理;

    3.1.3 Kafka应用场景

    Kafka和其他组件比较,具有消息持久化、高吞吐、分布式、多客户端支持、实时等特性,适用于离线和在线的消息消费,如常规的消息收集、网站活性跟踪、聚合统计系统运营数据(监控数据)、日志收集等大量数据的互联网服务的数据收集场景。具体应用场景如下:

    1. 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如Hadoop、Hbase、Solr等;
    2. 消息系统:解耦和生产者和消费者、缓存消息等;
    3. 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到Hadoop、数据仓库中做离线分析和挖掘;
    4. 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告;
    5. 流式处理:比如spark streaming和storm;
    6. 事件源;

    在这里插入图片描述

    3.2 rabbitMQ原理简介

    采用Erlang语言实现的AMQP协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。RabbitMQ发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。

    优点

    • 由于erlang语言的特性,mq性能较好,高并发;
    • 健壮、稳定、易用、跨平台、支持多种语言、文档齐全;
    • 有消息确认机制和持久化机制,可靠性高;
    • 高度可定制的路由;
    • 管理界面较丰富,在互联网公司也有较大规模的应用;
    • 社区活跃度高;

    缺点

    • 尽管结合erlang语言本身的并发优势,性能较好,但是不利于做二次开发和维护;
    • 实现了代理架构,意味着消息在发送到客户端之前可以在中央节点上排队。
    • 此特性使得RabbitMQ易于使用和部署,但是使得其运行速度较慢,因为中央节点增加了延迟,消息封装后也比较大;
    • 需要学习比较复杂的接口和协议,学习和维护成本较高;

    3.3 对比分析

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    应用方面:

    • RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上。
    • kafka它主要用于处理活跃的流式数据,大数据量的数据处理上。

    架构模型方面:

    • RabbitMQ遵循AMQP协议,RabbitMQ的broker由Exchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。rabbitMQ以broker为中心;有消息的确认机制。
    • kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,消息的消费信息保存的客户端consumer上,consumer根据消费的点,从broker上批量pull数据;无消息确认机制。

    吞吐量:

    • rabbitMQ在吞吐量方面稍逊于kafka,他们的出发点不一样,rabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘。
    • kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度,消息处理的效率很高。

    可用性方面:

    • rabbitMQ支持miror(镜像)的queue,主queue失效,miror queue接管。
    • kafka的broker支持主备模式。

    集群负载均衡方面:

    • rabbitMQ的负载均衡需要单独的loadbalancer进行支持。

    • kafka采用zookeeper对集群中的broker、consumer进行管理,可以注册topic到zookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上。

    总结
    Kafka 目前已成为大数据系统在异步和分布式消息之间的最佳选择。

    4 纯/准实时计算

    4.1 Spark原理简介

    Spark最初由美国加州伯克利大学(UCBerkeley)的AMP实验室于2009年开发,Spark是一个基于内存的分布式批处理引擎,可用于构建大型的、低延迟的数据分析应用程序。Spark是一站式解决方案,集批处理、实时流计算、交互式查询、图计算与机器学习与一体。它的架构图如下图所示:
    Spark架构
    Spark SQL:Spark中用于结构化数据处理的模块。
    Structured Streaming:构建在Spark SQL引擎上的流式数据处理引擎。
    Spark Streaming:实时计算框架。
    Mlib:是用于机器学习的框架
    GraphX:图计算
    Spark R:R语言分析

    4.1.1 Spark特点:

    Spark具有如下几个主要特点:

    • 运行速度快:使用DAG执行引擎以支持循环数据流与内存计算。
    • 容易使用:支持使用Scala、Java、Python和R语言进行编程,可以通过Spark Shell进行交互式编程。
    • 通用性:Spark提供了完整而强大的技术栈,包括SQL查询、流式计算、机器学习和图算法组件。
    • 运行模式多样:可运行于独立的集群模式中,可运行于Hadoop中,也可运行于Amazon EC2等云环境中,并且可以访问HDFS、Cassandra、HBase、Hive等多种数据源。

    4.1.2 Spark适用场景:

    • 数据处理,ETL(抽取、转换、加载)
    • 机器学习。如:可用于自动判断淘宝买家的评论是好评还是差评。
    • 交互式分析:可用于查询Hive数据仓库。
    • 特别使用与迭代计算,数据重复利用场景。
    • 流计算:流处理可用于页面点击浏览分析,推荐系统,舆情分析等实时业务。

    4.1.3 Spark Streaming介绍:

    Spark Streaming是Spark核心API的一个扩展,一个实时计算框架。具有可扩展性、高吞吐量、可容错性等特定。

    在这里插入图片描述
    Spark Streaming计算基于DStream,将流式计算分解成一系列短小的批处理作业。Spark引擎将数据生成最终结果数据。使用DStream从Kafka和HDFS等源获取连续的数据流,DStreams由一系列连续的RDD组成,每个RDD包含确定时间间隔的数据,任何对DStreams的操作都转换成对RDD的操作。
    Spark Streaming微批处理

    4.2 Flink原理简介

    Flink是一款分布式、高性能、高可用、高精确的为数据流应用而生的开源流式处理框架。Flink的核心是在数据流上提供数据分发、通信、具备容错的分布式计算。同时,Flink在流处理引擎上提供了批流融合计算能力,以及SQL表达能力。

    4.2.1 Flink特点

    • Streaming-first、流处理引擎。
    • Fault-tolerant,容错,可靠性,checkpoint。
    • Scalable,可扩展性,1000节点以上。
    • Performance,性能,高吞吐量, 低延迟。

    4.2.2 Flink关键特性

    • 低延时:提供ms级时延的处理能力。
    • Exactly Once:提供异步快照机制,保证所有数据真正处理一次。
    • HA:JobManager支持主备模式,保证无单点故障。
    • 水平扩展能力:TaskManager支持手动水平扩展。

    4.2.3 Hadoop兼容性

    • Flink能够支持Yarn,能够从HDFS和HBase中获取数据。
    • 能够使用所有的Hadoop的格式化输入和输出。
    • 能够使用Hadoop原有的Mappers和Reducers,并且能与FLink的操作混合使用。
    • 能够更快的运行Hadoop作业。

    4.2.4 Flink 应用场景

    Flink最适合的应用场景是低延时的数据处理场景:高并发处理数据,实验毫秒级,且兼具可靠性。
    典型应用场景有:

    • 互联网金融业务。
    • 点击流日志处理。
    • 舆情监控。

    4.3 对比分析

    • Spark Streaming由于其底层的架构(基于批处理做流处理)依然是batch,batch的数据是有边界的,不是真正意义的流式处理,无法实现毫秒级的流计算(只能秒级),因此在追求实时的环境下,仍然需要采用流计算框架(如Storm或者Flink)
    • 这几年Flink发展势头迅猛,在国内先是阿里巴巴在17年逐渐将实时处理转移至Flink,然后大量修改并回馈源码,阿里巴巴内部将Flink改为Blink。饿了么,美团也在大量使用Flink。
    • Flink 大有替代Spark Streaming的趋势

    5 可视化展示(插件介绍)

    5.1 Echarts

    ECharts 是一个使用 JavaScript 实现的开源可视化库。

    特点

    • ECharts 由百度研发,遵循 Apache-2.0 开源协议,免费商用

    • 基于Canvas,适用于数据量比较大的情况。

    • ECharts 兼容当前绝大部分浏览器(IE8/9/10/11ChromeFirefoxSafari等)及兼容多种设备,可随时随地任性展示。

    • 创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验,赋予了用户对数据进行挖掘、整合的能力。

    • 支持折线图(区域图)、柱状图(条状图)、散点图(气泡图)、K线图、饼图(环形图)、雷达图(填充雷达图)、和弦图、力导向布局图、地图、仪表盘、漏斗图、事件河流图等12类图表。

    • 提供标题,详情气泡、图例、值域、数据区域、时间轴、工具箱等7个可交互组件,支持多图表、组件的联动和混搭展现。
      /Echarts

    5.2 DataV

    DataV 是阿里云出品的拖拽式可视化工具。

    特点

    • 收费,不支持二次开发。

    • DataV`易于上手,能够满足会议展览、业务监控、风险预警、地理信息分析等多种业务的展示需求。

    • 它是开发天猫双11、阿里云城市大脑同款数据可视化应用。

    示例

    DataV

    5.3 D3.js

    D3 的全称是(Data-Driven Documents),是一个 JavaScript的函数库,主要是用来做数据可视化。
    特点

    • D3 已经将生成可视化的复杂步骤精简到了几个简单的函数,大大简化了 JavaScript 操作数据的难度
    • 本质上是 JavaScript,需要具备一些JavaScript基础,不适合初学者
    • 开源免费

    5.4 AntV

    AntV是蚂蚁金服-体验技术部-数据图形组的开源项目,原名是G2 (The Grammar Of Graphics)

    特点

    • 收费
    • 由纯 JavaScript 编写,集成了大量的统计工具,支持多种坐标系绘制

    5.5 对比分析

    • 如果希望开发脑海中任意想象到的图表,那就选择 D3.js。
    • 如果希望开发几种固定种类的、十分大众化的图表,选择 Echarts等。

    6 案例

    待更新

    展开全文
  • 实验三 进程模拟调度

    2019-10-08 07:11:06
    1.目的和要求 实验目的 用高级语言完成一个进程调度程序,以加深对进程的概念及进程调度算法的理解。...完成两个算法(简单时间片轮转法、多级反馈队列调度算法)的设计、编码和调试工作,完成实验报告。 1)每...
  • 编程实现四种调度算法: (1) 先来先服务算法 (2) 短作业优先算法 (3) 优先权算法 (4) 基于时间片的多级反馈队列算法 ⒉ 基本要求 (1) 通过若干个实例实现各种算法的优劣性对比; (2) 结果要求可视化展示 ⒊ 实现...
  • 1.目的和要求 用高级语言完成一个进程调度程序,以加深对进程的概念及进程调度...完成两个算法(简单时间片轮转法、多级反馈队列调度算法)的设计、编码和调试工作,完成实验报告。 1)每个进程有一个进程控制块(...
  • 实验三 进程调度模拟程序 1.目的和要求 实验目的 用高级语言完成一个进程调度程序,以加深对进程的概念及...完成两个算法(简单时间片轮转法、多级反馈队列调度算法)的设计、编码和调试工作,完成实验报告。 ...
  • 实验三进程调度

    2016-05-12 20:36:00
    1.目的和要求 1.1.实验目的 用高级语言完成一个进程调度程序,以加深对...进程调度算法:采用最高优先级优先的调度算法(即把处理机分配给优先级最高的进程)和先来先服务(若优先级相同)算法。 (1). 每个进程...
  • 进程调度模拟程序

    2015-05-14 08:33:00
    1. 目的和要求 1.1. 实验目的 用高级语言完成一个进程调度程序...进程调度算法:采用最高优先级优先的调度算法(即把处理机分配给优先级最高的进程)和先来先服务(若优先级相同)算法。 (1). 每个进程有一个进程...
  • 实验三进程调度模拟程序 1.目的和要求 1.1.实验目的 用高级语言完成一个进程调度程序,以...进程调度算法:采用最高优先级优先的调度算法(即把处理机分配给优先级最高的进程)和先来先服务(若优先级相同)算...
  • 操作系统—— 5 调度

    2020-04-03 23:56:35
    调度1 背景2 调度原则2.1 调度策略2.2 程序执行模型2.3 比较调度算法的准则2.4 吞吐量vs延迟2.5 公平的目标3 调度算法3.1 先来先服务(FIFS)3.2 短进程优先3.3 最高响应比优先 1 背景 什么时候切换,根据什么原则...
  • 实验三 进程调度模拟程序 专业:物联网工程 姓名:王鸾 学号:201306104128 一、 实验目的和要求 目的: 用高级语言完成一个进程...进程调度算法:“时间片轮转法”调度算法对N个进程进行调度。 二、实验内...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 683
精华内容 273
关键字:

多级队列调度算法可视化界面