操作系统课程设计并发进程的模拟

合集下载

操作系统课程设计报告-进程调度的模拟实现

操作系统课程设计报告-进程调度的模拟实现

操作系统课程设计报告专业计算机科学与技术学生姓名班级学号指导教师完成日期博雅学院ﻬ题目:进程调度的模拟实现的模拟实现一、设计目的本课程设计是学习完“操作系统原理”课程后进行的一次全面的综合训练,通过课程设计,更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。

在多道程序和多任务系统中,系统内同时处于就绪状态的进程可能有若干个。

也就是说能运行的进程数大于处理机个数。

为了使系统中的进程能有条不紊地工作,必须选用某种调度策略,选择一进程占用处理机。

要求学生设计一个模拟处理机调度算法,以巩固和加深处理机调度的概念.二、设计内容1)概述选择一个调度算法,实现处理机调度。

设计要求:1)进程调度算法包括:时间片轮转法,短作业优先算法,动态优先级算法。

2)可选择进程数量3)本程序包括三种算法,用C或C++语言实现,执行时在主界面选择算法(可用函数实现),进入子页面后输入进程数,(运行时间,优先数由随机函数产生),执行,显示结果。

调度时总是选取优先数最大的进程优先运行2.每个进程的优先数,运行时间,由程序任意指定.3.为了调度方便,把进程按给定优先级(动态优先级算法中)从小到大排成一个队列。

按给定运行时间(短作业优先)从小到大排成一个队列用一个变量作为队首指针,指向队列的第一个进程。

4.处理机调度总是选队首进程运行。

由于本实验是模拟处理机调度,所以被选中的进程并不实际的启动运行,而是执行:优先数-1(动态优先级算法中)要求运行时间-1来模拟进程的一次运行。

5.进程运行一次后,若要求运行时间不等于0,则再将它加入队列(动态优先级算法中:按优先数大小插入.),且改变队首指针:若要求运行时间=0,则把它的状态改为完成(C)状态,且退出队列。

(5)对于遇到优先数一致的情况,采用FIFO策略解决.3。

概要设计(1)本程序用两种算法对五个进程进行调度,每个进程可有三个状态,并假设初始状态为就绪状态。

进程管理模拟系统课程设计

进程管理模拟系统课程设计

进程管理模拟系统课程设计一、课程目标知识目标:1. 学生能理解进程管理的基本概念,掌握进程的创建、同步、通信及调度等原理;2. 学生能运用所学知识分析进程管理模拟系统的运作过程,理解操作系统的进程管理功能;3. 学生了解进程管理在计算机系统中的应用,明确其在操作系统中的重要性。

技能目标:1. 学生能够独立设计简单的进程管理模拟系统,具备实际操作能力;2. 学生通过实践,提高程序设计能力,学会使用相关工具分析进程管理问题;3. 学生学会运用进程同步和通信技术解决实际问题,培养解决问题的能力。

情感态度价值观目标:1. 学生通过学习进程管理,培养团队合作精神,增强沟通与协作能力;2. 学生在学习过程中,培养严谨、细致的科学态度,提高对操作系统的兴趣;3. 学生认识到操作系统在计算机系统中的核心地位,增强学习操作系统的自觉性和责任感。

本课程旨在帮助学生掌握进程管理的核心知识,培养实际操作和解决问题的能力,同时注重培养学生的团队协作和情感态度,使他们在学习过程中形成正确的价值观。

课程针对学生的年级特点,注重理论与实践相结合,以操作系统的进程管理为基础,引导学生运用所学知识解决实际问题。

在教学过程中,教师需关注学生的学习进度,及时调整教学策略,确保课程目标的实现。

二、教学内容1. 进程管理基本概念:进程与线程的定义、进程的状态与转换、进程控制块(PCB)的作用;2. 进程同步与互斥:同步机制、互斥锁、生产者-消费者问题、读者-写者问题;3. 进程通信:管道、消息队列、信号量、共享内存;4. 进程调度:调度算法(如FCFS、SJF、RR等)、调度策略、调度性能分析;5. 进程管理模拟系统设计:系统架构、模块划分、关键算法实现;6. 实践操作:使用相关工具(如Linux系统调用、C语言编程等)设计并实现一个简单的进程管理模拟系统。

教学内容根据课程目标进行组织,以教材中关于进程管理的章节为基础,结合学生实际情况进行合理安排。

操作系统课程设计进程调度模拟

操作系统课程设计进程调度模拟

计算机科学与工程学院综合设计报告设计名称:操作系统软件综合设计设计题目:进程调度算法模拟学生学号:专业班级:学生姓名:学生成绩:指导教师(职称):课题工作时间:2013-6-17 至2013-6-28 说明:1、报告中的第一、二、三项由指导教师在综合设计开始前填写并发给每个学生;四、五两项(中英文摘要)由学生在完成综合设计后填写。

2、学生成绩由指导教师根据学生的设计情况给出各项分值及总评成绩。

3、指导教师评语一栏由指导教师就学生在整个设计期间的平时表现、设计完成情况、报告的质量及答辩情况,给出客观、全面的评价。

4、所有学生必须参加综合设计的答辩环节,凡不参加答辩者,其成绩一律按不及格处理。

答辩小组成员应由2人及以上教师组成。

5、报告正文字数一般应不少于5000字,也可由指导教师根据本门综合设计的情况另行规定。

6、平时表现成绩低于6分的学生,取消答辩资格,其本项综合设计成绩按不及格处理。

7、此表格式为武汉工程大学计算机科学与工程学院提供的基本格式(适用于学院各类综合设计),各教研室可根据本门综合设计的特点及内容做适当的调整,并上报学院批准。

成绩评定表学生姓名:学号:班级:答辩记录表指导教师评语4.摘要 (II)ABSTRACT (III)第一章课题背景 (1)1.1课题背景 (1)1.2进程调度简介 (1)1.3课题目的 (3)1.4课题意义 (3)第二章设计简介及设计方案论述 (4)2.1步骤简介 (4)2.2设计要点 (4)2.3具体方案 (4)第三章详细设计 (7)3.1设计数据结构 (7)3.2模拟进程调度 (7)3.3算法流程图 (7)3.4主要函数定义 (12)第四章设计结果及分析 (13)4.1创建进程 (13)4.2选择进程调度 (13)4.3先来先服务调度 (13)4.4时间片轮转调度 (14)4.5优先级调度 (14)4.6多级反馈队列调度 (15)4.7性能分析 (15)总结 (17)致谢 (18)参考文献 (19)附录 (20)在OS中调度的实质是一种资源分配,因而调度算法是指:根据系统的资源分配策略所规定的资源分配算法。

操作系统课程设计报告-进程调度算法模拟

操作系统课程设计报告-进程调度算法模拟

1.课程设计的目的《操作系统原理》课程设计我们专业实践性环节之一,是学习完《操作系统原理》课程后进行的一次较全面的综合练习。

其目的在于加深对操作系统的理论、方法和基础知识的理解,掌握操作系统结构、实现机理和各种典型算法,系统地了解操作系统的设计和实现思路,培养学生的系统设计能力,并了解操作系统的发展动向和趋势。

2.课程设计的内容及要求先来先服务、短作业优先、时间片轮转、基于静态优先级的调度,基于高响应比优先的动态优先级调度算法实现,能够输出调度情况,并计算周转时间和平均周转时间。

要求使用链表,进程个数由用户提供,按照进程的实际个数生成PCB,程序能够让用户选择使用哪种调度算法,能够在Linux环境运行并验证结果。

程序要考虑用户界面的友好性和使用方便性。

进程基本信息可从文件读入,也可手动输入。

3、设计原理3.1先来先服务调度算法每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源创建进程,然后放入就绪队列3.2短作业优先调度算法短作业优先调度算法是从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。

3.3时间片轮转调度算法系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把CPU分配给队首进程,并令其执行一个时间片。

时间片的大小从几ms到几百ms。

当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的末尾;然后,再把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。

3.4静态优先级调度算法把处理机分配给优先级最高的进程,使之执行。

但在其执行期间,只要出现了另一个比其优先级更高的进程,调度程序就将处理机分配给新到的优先级最高的进程。

这样就可以保证紧迫性作业优先运行。

3.5最高响应比优先的动态优先级调度算法优先权调度算法是为了照顾紧迫型作业,使之在进入系统后便获得优先处理,引入最高优先权优先调度算法。

进程模拟课程设计报告

进程模拟课程设计报告

操作系统课程设计报告书课程设计题目:模拟操作系统进程管理专业:计算机科学与技术班级:计算机 * * 班小组成员:成员及分工:1、2、3、4、一、课程设计目的课程设计的目的是模拟操作系统进程管理。

二、课程设计要求课程设计要求使用一种编程语言能够模拟进程创建,进程执行,进程阻塞,进程消亡和进程唤醒。

三、系统环境支持及语言选择Window操作系统,C语言编写。

四、系统框架构成五、系统功能说明本次模拟进程调度使用的是FIFO算法。

main()主函数int init() 进程初始化void drawmat( ) 汉字输入定义int enqueue(PCB *head , PCB *node) 进程入队PCB * dequeue(PCB *head) 进程出队int create() 创建进程int fexcute() 将进程调入运行队列int run() 运行进程int wake() 唤醒进程int block() 阻塞进程int outputqueue(PCB *head) 输出进程状态int help() 帮助菜单int leave() 退出程序六、用户使用说明当用户进入欢迎界面后,输入任意键,系统自动初始化,然后输入您要创建的多个进程,当输入完成后,可以按0 0表示输入结束。

程序会默认创建进程为就绪队列,接着会弹出帮助菜单,用户只要按帮助菜单的字母按钮执行相应的进程调度、进程阻塞、进程运行等操作,以实现操作系统进程管理的模拟。

七、运行界面如下八、源代码#include "stdio.h"#include"graphics.h"#include "dos.h"#include "stdlib.h"#include "conio.h"#define SEC 3#define NULL 0char han1S[]={0x00,0x80,0x00,0x80,0xFC,0x80,0x04,0xFC,0x45,0x04,0x46,0x48,0x28,0x40,0x28, 0x40,0x10,0x40,0x28,0x40,0x24,0xA0,0x44,0xA0,0x81,0x10,0x01,0x08,0x02,0x0E ,0x0C,0x04,};char han2S[]={0x00,0x00,0x41,0x84,0x26,0x7E,0x14,0x44,0x04,0x44,0x04,0x44,0xF4,0x44,0x14, 0xC4,0x15,0x44,0x16,0x54,0x14,0x48,0x10,0x40,0x10,0x40,0x28,0x46,0x47,0xFC, 0x00,0x00,};char han3S[]={0x02,0x20,0x42,0x20,0x22,0x28,0x2F,0xFC,0x02,0x20,0x02,0x20,0xE2,0x20,0x22, 0x28,0x2F,0xFC,0x22,0x20,0x22,0x20,0x22,0x20,0x24,0x20,0x50,0x26,0x8F,0xFC, 0x00,0x00,};char han4S[]={0x04,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x02,0x80,0x02,0x80,0x02, 0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x08,0x20,0x10,0x10,0x20,0x10,0x40,0x0E, 0x80,0x04,};char han5S[]={0x10,0x10,0x11,0xF8,0x11,0x10,0x11,0xF0,0xFC,0x04,0x17,0xBE,0x14,0xA4,0x1F, 0xBC,0x30,0x40,0xD0,0x44,0x1F,0xFE,0x10,0xE0,0x11,0x50,0x12,0x4E,0x54,0x44, 0x20,0x40,};char han6S[]={0x09,0x00,0x09,0x00,0x09,0x04,0x11,0xFE,0x12,0x80,0x32,0x80,0x54,0x90,0x98, 0xF8,0x10,0x80,0x10,0x80,0x10,0x88,0x10,0xFC,0x10,0x80,0x10,0x80,0x10,0x80, 0x10,0x80,};char han7S[]={0x00,0x38,0x7F,0xC0,0x04,0x00,0x04,0x10,0x08,0x20,0x3F,0xC0,0x01,0x00,0x02, 0x20,0x04,0x10,0x3F,0xF8,0x01,0x08,0x09,0x20,0x09,0x10,0x11,0x08,0x25,0x08, 0x02,0x00,};char han8S[]={0x10,0x80,0x10,0x40,0x20,0x48,0x27,0xFC,0x48,0x80,0xF9,0x10,0x12,0x08,0x27, 0xFC,0x41,0x24,0xF9,0x20,0x41,0x20,0x01,0x20,0x1A,0x22,0xE2,0x22,0x44,0x1E, 0x08,0x00,};char han9S[]={0x11,0x10,0x11,0x14,0x1F,0xFE,0x11,0x10,0xFD,0x18,0x13,0xFC,0x32,0x08,0x3B, 0xF8,0x56,0x08,0x53,0xF8,0x90,0x40,0x1F,0xFE,0x10,0x40,0x10,0xB0,0x11,0x0E, 0x16,0x04,};char han10S[]={0x10,0x00,0x10,0x08,0x10,0x88,0x12,0x48,0xFE,0x68,0x12,0x28,0x16,0x08,0x1A, 0x08,0x32,0x08,0xD2,0x08,0x12,0x48,0x12,0x88,0x13,0x14,0x12,0x22,0x50,0x42, 0x20,0x80,};char han11S[]={0x02,0x20,0x42,0x20,0x22,0x28,0x2F,0xFC,0x02,0x20,0x02,0x20,0xE2,0x20,0x22, 0x28,0x2F,0xFC,0x22,0x20,0x22,0x20,0x22,0x20,0x24,0x20,0x50,0x26,0x8F,0xFC, 0x00,0x00,};char han12S[]={0x08,0x04,0x1D,0xFE,0xF1,0x04,0x11,0x04,0x11,0x04,0xFF,0x04,0x11,0xFC,0x38, 0x00,0x37,0xFE,0x54,0x20,0x50,0x28,0x91,0xFC,0x10,0x20,0x10,0x24,0x17,0xFE, 0x10,0x00,};char han13S[]={0x10,0x40,0x1F,0x7C,0x28,0x90,0x45,0x08,0x01,0x00,0x7F,0xFE,0x40,0x02,0x9F, 0xF4,0x10,0x10,0x1F,0xF0,0x10,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0, 0x10,0x00,};char han14S[]={0x00,0x08,0x13,0xFC,0xFA,0x48,0x22,0x48,0x23,0xF8,0x22,0x48,0xFA,0x48,0x23, 0xF8,0x20,0x40,0x20,0x50,0x23,0xF8,0x3C,0x40,0xE0,0x40,0x40,0x44,0x0F,0xFE, 0x00,0x00,};void drawmat(char *mat,int matsize,int x,int y,int color){int i,j,k,n;n=(matsize-1)/8+1;for(j=0;j<matsize;j++)for(i=0;i<n;i++)for(k=0;k<8;k++)if(mat[j*n+i]&(0x80>>k))putpixel(x+i*8+k,y+j,color);}/*定义结构体*/typedef struct PCB{int PID;int UID;struct PCB * next;}PCB;PCB *really , *excute , *wait;/*create queue header *//*queue operation 入队*/int enqueue(PCB *head , PCB *node) {PCB *p;p = head;if(p -> next == NULL){head -> next = node;return 1;}while(p){if(p -> next == NULL){p -> next = node;return 1;}else p = p -> next;}}/*enquue*//*dequeue 出队列 */PCB * dequeue(PCB *head){PCB *p;p = head;if(p -> next == NULL){return NULL;}else{p = p -> next;head -> next = p -> next;p -> next = NULL;return p;}/*head to next*/}/*dequeue*//*PCB operate*//*新建进程*/int create(){PCB *p;p = (PCB*)malloc(sizeof(PCB));p -> next = NULL;printf("input PID and UID to a new process\n");scanf("%d %d",&p -> PID,&p -> UID);if(enqueue(really , p))printf("create a process: PID = %d UID = %d\n", p -> PID , p -> UID);elseprintf("create Failed\n");}/*create*//*执行 fexcute*/int fexcute(){PCB *p = dequeue(really);if(p == NULL){printf("NO process in queue \n");return 0;}else{enqueue(excute , p);printf("add a process into excute queue process: PID = %d UID= %d \n" ,p->PID , p->UID);return 1;}}/*excute*/int wake(){PCB *p = dequeue(wait);if(p == NULL){ printf("NO process in queue \n");return 0;}else{ enqueue(really , p);printf("add a process into wait really process: PID = %d UID= %d \n" ,p->PID , p->UID);return 1;}}int block(){PCB *p = dequeue(excute);if(p == NULL){printf("NO process in queue \n");return 0;}else{enqueue(wait , p);printf("add a process into wait queue process: PID = %d UID= %d \n" ,p->PID , p->UID);return 1;}}/*输出队列 outputqueue*/int outputqueue(PCB *head){PCB *p;if(head -> next == NULL){/*队列为空*/printf("queue is null \n");return 1;}p = head -> next;while(p){printf("PID = %d UID = %d \n" , p -> PID , p -> UID);p = p -> next;}return 0;}/*output输出*/int output(){ printf("REALLLY QUEUE:\n");outputqueue(really);printf("EXCUTE QUEUE: \n");outputqueue(excute);printf("WAIT QUEUE: \n");outputqueue(wait);}/*init 初始化*/int init(){ int i;PCB *p;clrscr();really = (PCB*)malloc(sizeof(PCB));really -> next=NULL;excute = (PCB*)malloc(sizeof(PCB));excute -> next=NULL;wait = (PCB*)malloc(sizeof(PCB));wait -> next = NULL;printf("_________________________PROCESSSECHUDLE___________________________ \n");printf("now is initing");for(i=0;i<18;i++){printf(". ");delay(10000000000);}printf("\ninput PID and UID as integer , 0 0 as over\n");while(1){p = (PCB*)malloc(sizeof(PCB));p -> next = NULL;scanf("%d %d",&p -> PID , &p -> UID);if(p -> PID == 0 && p -> UID == 0)break;else{if(enqueue(really , p)){printf("new process PID = %d UID = %d added!\n",p -> PID , p -> UID); }else return 0;}}return 1;}/*init*//*运行一个process*/int run(){ PCB *p = excute;int s = SEC;if(excute -> next == NULL){printf("no process in excute queue \n");return 0;}else{p = excute -> next;printf("system will sleep %ds as process running\n",s);sleep(3);printf("process: PID = %d UID= %d excute successed..\n" , p -> PID , p -> UID ); excute -> next = p -> next;free(p);}}/*run*//*离开*/int leave(){ int COMMAND;printf("Are you sure to leave? YES-(1), NO-(2)\n");scanf("%d",&COMMAND);if(COMMAND==1){clrscr();exit(0);}if(COMMAND==2){printf("\n");help();}}int help(){ printf("__________________________HELP MENU____________________________\n");printf("\t-h HELP show help option\n");printf("\t-c CREATE create a new process , and put to really queue\n"); printf("\t-b BLOCK block a process in excute queue\n");printf("\t-w WAKE wake a process in wait queue\n");printf("\t-e EXCUTE excute a process in really queue\n");printf("\t-s SUSPEND suspend a process in excute queue\n");printf("\t-o OUTPUT output all processes in queues\n");printf("\t-r RUN excute a process in excute queue\n");printf("\t-x EXIT exit this program\n");printf("_______________________________________________________________\n") ;printf("\t type 'H' will show this menu\n");}int main(){char COMMAND = NULL;int i;int gdriver=DETECT,gmode;initgraph(&gdriver,&gmode,"");setbkcolor(LIGHTBLUE);setcolor(21);for(i=40;i<=600;i+=12){rectangle(i,40,i+10,49);rectangle(i,451,i+10,460);}for(i=40;i<=450;i+=12){rectangle(40,i,49,i+10);rectangle(601,i,610,i+10);}setcolor(19);rectangle(150,100,480,410);rectangle(145,95,475,405);drawmat(han1S,16,200,230,BLUE); drawmat(han2S,16,230,230,BLUE); drawmat(han3S,16,260,230,BLUE); drawmat(han4S,16,290,230,BLUE); drawmat(han5S,16,320,230,BLUE); drawmat(han6S,16,350,230,BLUE); drawmat(han7S,16,380,230,BLUE); drawmat(han8S,16,410,230,BLUE); drawmat(han9S,16,220,300,BLUE); drawmat(han10S,16,250,300,BLUE); drawmat(han11S,16,280,300,BLUE); drawmat(han12S,16,310,300,BLUE); drawmat(han13S,16,340,300,BLUE); drawmat(han14S,16,370,300,BLUE); getch();closegraph();if( init() != 1){printf("init falied ! \n ");getch();exit(0);}else{printf("init...OK\n");output();help();}while(1){/*当三队列都不空执行调度 */ printf(">");scanf("%c",&COMMAND);switch(COMMAND){ case '\n': break;case 'H':case 'h': help(); break;case 'C':case 'c': create(); break; case 'B':case 'b': block(); break; case 'W':case 'w': wake(); break;case 'E':case 'e': fexcute(); break; case 'O':case 'o': output(); break; case 'X':case 'x': leave(); break; case 'R':case 'r': run(); break;}}}。

操作系统课程设计-进程同步模拟设计

操作系统课程设计-进程同步模拟设计

课程设计题目进程同步模拟设计——生产者和消费者问题学院计算机科学与技术学院专业计算机科学与技术班级0806姓名张方纪指导教师孙玉芬2010 年 1 月20 日课程设计任务书学生姓名:张方纪专业班级:计算机0806指导教师:孙玉芬工作单位:计算机科学与技术学院题目: 进程同步模拟设计——生产者和消费者问题初始条件:1.预备内容:阅读操作系统的进程管理章节内容,对进程的同步和互斥,以及信号量机制度有深入的理解。

2.实践准备:掌握一种计算机高级语言的使用。

要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)1.模拟用信号量机制实现生产者和消费者问题。

2.设计报告内容应说明:⑴需求分析;⑵功能设计(数据结构及模块说明);⑶开发平台及源程序的主要部分;⑷测试用例,运行结果与运行情况分析;⑸自我评价与总结:i)你认为你完成的设计哪些地方做得比较好或比较出色;ii)什么地方做得不太好,以后如何改正;iii)从本设计得到的收获(在编写,调试,执行过程中的经验和教训);iv)完成本题是否有其他方法(如果有,简要说明该方法);时间安排:设计安排一周:周1、周2:完成程序分析及设计。

周2、周3:完成程序调试及测试。

周4、周5:验收、撰写课程设计报告。

(注意事项:严禁抄袭,一旦发现,一律按0分记)指导教师签名:年月日系主任(或责任教师)签名:年月日进程同步模拟设计——生产者和消费者问题1课设任务本课程设计的任务在于,通过编写一个具体的有关操作系统进程同步互斥的经典问题,加强对操作系统实现进程间同步与互斥的机制的理解。

同时培养提出问题、发现知识、使用工具、解决问题的能力。

具体地,我们要编制出一个程序,利用PV原语以及进程创建、同步、互斥、销毁等相关的系统调用来模拟“生产者—消费者”问题。

2背景介绍2.1“生产者—消费者”问题(the producer-consumerproblem)问题描述:一组生产者向一组消费者提供消息,它们共享一个有界缓冲区n,生产者向其中投放消息,消费者从中取得消息。

操作系统实验报告 并发程序设计

操作系统实验报告 并发程序设计

《计算机操作系统》实验报告(一)学号:030702412 姓名:陈楠学院:数计学院专业:计算机类年级:2007级班级:4班实验时间:2009-2010学年第一学期指导教师:丁善镜、黄志华目录1、实验题目 (3)2、实验目的 (3)3、实验环境 (3)4、实验原理 (3)5、实验内容 (3)5.1、fork()函数机理探索 (3)5.1.1、原始代码段 (3)5.1.2、代码段修改一 (3)5.1.3、结论(1) (4)5.1.4、fock()函数原理 (4)5.1.5、代码段修改二 (4)5.2、并发执行测猜测 (5)5.2.1、并发执行改进 (5)5.2.2、代码段修改(3) (5)5.3、小结 (6)1、实验题目2、实验目的掌握在程序中创建新进程的方法,观察并理解多道程序并发执行的现象。

3、实验环境Red Hat Enterprise Linux 54、实验原理fork():建立子进程。

子进程得到父进程地址空间的一个复制。

返回值:成功时,该函数被调用一次,但返回两次,fork()对子进程返回0,对父进程返回子进程标识符(非0值)。

不成功时对父进程返回-1,没有子进程。

5、实验内容分析一下程序运行时其输出结果有哪几种可能性,然后实际调试该程序观察其实际输出情况,比较两者的差异,分析其中的原因。

5.1、fork()函数机理探索5.1.1、原始代码段#include<stdio.h>#include<unistd.h>void main (void){ int x=5;if( fork( ) ){x+=30;printf (“%d\n”,x);}elseprintf(“%d\n”,x);printf(“%d\n”,x);}为了了解fork()函数的机理,了解fork()是从哪里开始重复执行代码,特将代码做了第一次修改5.1.2、代码段修改一#include<stdio.h>#include<unistd.h>图1 验证fork()函数原理 图2 验证是否共享内存 void main (void){ int x=5;printf(“start \n”);if( fork( ) ){x+=30;printf (“father %d \n”,x);}elseprintf(“child %d \n”,x);printf(“out%d \n”,x);}右侧为第一次修改后代码的输出(图1)5.1.3、 结论(1)fock() 对于该语句之前的程序段只执行一次fock() 对于该语句返回两次值,并针对两次返回值依次执行之后的语句5.1.4、 fock()函数原理 被fork 创建的新进程叫做自进程。

模拟进程调度功能的设计与实现操作系统课程设计(JAVA版本)

模拟进程调度功能的设计与实现操作系统课程设计(JAVA版本)

操作系统课程设计--进程调度子系统模拟实现一、设计内容及意义1.课程设计内容使用java语言或C++语言编程实现模拟操作系统进程调度子系统的基本功能;实现先来先服务、时间片轮转、多级反馈轮转法对进程进行的调度过程;掌握各个调度算法的特点。

2.该课程设计意义➢理解进程调度的概念➢深入了解进程控制块的功能、进程的创建、删除以及进程各个状态间的转换过程➢从实用的角度对《数据结构》课程内容进行更深入理解和更熟练的应用➢进一步练习对Java及C++语言的熟练使用二、设计方案1.硬件环境PC一台2.开发语言及工具➢操作系统:MS windows XP➢C++版:Visual Studio 2008 + MFC➢Java版:Eclipse 3.4 + Java Swing3.设计思路➢系统设备表用于存取调度过程中进程可申请的资源➢进程控制块主要负责具体进程信息的保存➢等待队列、就绪队列、完成队列用于保存执行过程的状态信息➢进程调度进程(类、线程)在就绪队列与等待队列之间进行调度➢主界面显示调度过程的三个队列的状态信息➢用户创建进程放入就绪队列等待调度三、功能模块设计1.进程状态转换2.PCB信息➢主要负责保存各进程基本信息➢提供外部状态设置和读取接口3.系统设备类➢系统设备的基本信息➢设备状态设置、读取接口4.调度类➢向就绪队列添加新创建进程➢从就绪队列取相应进程执行➢将执行阻塞进程放入等待队列➢检测系统设备表,分配、释放设备、唤醒等待进程➢执行完成程序放入完成队列(仅为保存状态,非系统部分)➢提供获取执行状态的外部接口,即各个队列数据的获取5.视图类➢提供用户操作接口(调度策略选择、进程创建)➢显示各队列状态信息➢创建进程调度类线程,调用调度类的接口四、程序总控流程图1.用户接口、调度算法、进程状态转换关系示意系统总体设计页面 12.调度算法基本工作流程示意页面1进程调度框架五、数据结构设计1.PCB(进程基本信息)➢类结构➢说明1.pid进程ID2.pName进程名erName进程用户4.priority进程优先级5.subtime进程提交时间6.totalTime进程需要执行的总时间7.runtime进程已经运行时间8.dcReqlst当前进程所需要的设备请求表2.Dispatcher(进程调度进程)➢类结构➢说明1.sysTime系统时间2.isContention当前调度是否为抢占方式3.prelst就绪队列4.waitlst等待队列5.finishlst完成队列6.executing正在执行的进程7.sysDclst系统设备表3.Device(系统设备)➢➢说明1.dcid设备标识2.dcType设备类型3.dcTime该设备一次I/O服务需要时间4.dcPid使用该设备的进程5.dcDisc设备描述6.dcLefTime设备剩余服务时间六、程序代码结构1.类层次关系2.详细说明➢Dispatcher定义进程调度进程的基本信息和接口➢FIFODispatcher、PLevelDispatcher、RRDispatcher、MRDispatcher 分别实现相应的调度算法➢Device为系统设备➢DeviceReq为进程设备请求,包括请求设备ID和时间七、代码实现分析1.算法分析(各算法过程见下流程图)➢设备的分配释放➢先来先服务➢优先级调度➢时间片轮转➢多级反馈轮转设备分配释放页面 1先进先出进程调度算法页面 1优先级进程调度算法(抢占式)页面 1时间片轮转调度算法页面 1多级反馈轮转调度算法(抢占式)页面 12.具体实现(代码部分有详细注释)➢进程的插入@Overridepublic void addPreProc(Process proc) {//按优先级加到就绪队列this.prelst.add(proc);int loc;for(loc=prelst.size()-2; loc>=0; loc--){//比proc大的元素后移一个位置Process temp = prelst.get(loc);if(proc.Priority<temp.Priority){prelst.set( loc+1, temp);}else{ //将proc放入空闲位置prelst.set( loc+1, proc);break;}}if(loc<0){prelst.set(0, proc);}}➢取出进程@Overridepublic Process delPreProc() {//取优先级最高者,即为第一个if(prelst.size()<=0){return null;}return this.prelst.remove(0); //返回最小一个}➢先进先出算法的调度@Overridepublic void run(int time) {int proctimeslice = 1; //假设处理器指令周期为1个时钟周期while(time>0){ //处理机运行time时间if(this.executing==null){ //没有进程占用处理机则空转this.executing = this.delPreProc();}else{ //执行当前进程Process proc = this.executing;//下一次执行需要的设备DcRequest req = proc.getNextReq();if(req!=null && req.getReqtime()<=proc.runtime){//进程需要请求设备,而且执行到请求时间this.addWaitProc(proc);this.executing = this.delPreProc();}else{ //无资源请求proc.run(proctimeslice);if(proc.isFinished()){//当前进程是已完成进程,放入完成队列,取下一进程proc.setFinishTime(Dispatcher.getBeginTime()+ Dispatcher.getRunTime());//设置当前执行结束时间this.addFinishProc(proc);this.executing = this.delPreProc();}}}super.processWaitlst(proctimeslice);++Dispatcher.runTime;--time;}}➢优先级抢占算法的调度@Overridepublic void run(int time, boolean isContention) {if(!isContention){ //非抢占方式this.run(time);return;}int proctimeslice = 1; //假设处理器时钟周期while(time>0){ //处理机运行time时间if(this.executing==null){ //没有进程占用处理机则空转this.executing = this.delPreProc();}else{ //执行当前进程Process proc = this.executing;//下一次执行需要的设备DcRequest req = proc.getNextReq();if(req!=null && req.getReqtime()<=proc.runtime){//进程需要请求设备,而且执行到请求时间//放入等待队列,取下一进程this.addWaitProc(proc);this.executing = this.delPreProc();}else{ //无资源请求proc.run(proctimeslice);if(proc.isFinished()){//当前进程是已完成进程,放入完成队列,取下一进程proc.setFinishTime(//设置当前执行结束时间Dispatcher.getBeginTime()+Dispatcher.getRunTime());this.addFinishProc(proc);this.executing = this.delPreProc();}}if(!this.prelst.isEmpty()){ //抢占Process preproc = this.prelst.get(0);if(this.executing.Priority>preproc.Priority){ //按优先级抢占this.addPreProc(this.executing);this.executing = this.delPreProc();}}}super.processWaitlst(proctimeslice);++Dispatcher.runTime;--time;}}➢时间片轮转@Overridepublic void run(int time) {int proctimeslice = 1; //假设处理器时钟周期while(time>0){ //处理机运行time时间if(this.executing==null){ //没有进程占用处理机则空转this.executing = this.delPreProc();}else{ //执行当前进程Process proc = this.executing;//下一次执行需要的设备DcRequest req = proc.getNextReq();if(req!=null && req.getReqtime()<=proc.runtime){//进程需要请求设备,而且执行到请求时间//放入等待队列,取下一进程this.addWaitProc(proc);this.executing = this.delPreProc();}else{ //无资源请求proc.run(proctimeslice);if(proc.isFinished()){//当前进程是已完成进程,放入完成队列,取下一进程proc.setFinishTime( //设置当前执行结束时间Dispatcher.getBeginTime()+Dispatcher.getRunTime());this.addFinishProc(proc);this.executing = this.delPreProc();}else{//如果当前时间片没有执行完,则从就绪队列头移到队列尾部this.addPreProc(this.executing);//当前执行进程放入就绪队列this.executing = this.delPreProc();//从就绪队列取下一个进程占用cpu}}}super.processWaitlst(proctimeslice);++Dispatcher.runTime;--time;}}➢多级反馈轮转抢占方式@Overridepublic void run(int time, boolean isContention) {int proctimeslice = 1; //假设处理器时钟周期while(true){--time;if(this.executing==null){ //没有进程占用处理机则空转this.executing = this.delPreProc();if(this.executing!=null){ //每调度一次重新计算时间片time = this.executing.getPriority()*3+1;}break;}else{ //执行当前进程Process proc = this.executing;//下一次执行需要的设备DcRequest req = proc.getNextReq();if(req!=null &&req.getReqtime()<=proc.runtime){//进程需要请求设备,而且执行到请求时间//TODO放入等待队列,取下一进程this.addWaitProc(proc);this.executing = this.delPreProc();break; //时间片未完,设备请求,重新调度}else{ //无资源请求proc.run(proctimeslice);if(proc.isFinished()){//当前进程是已完成进程,放入完成队列,取下一进程proc.setFinishTime(//设置当前执行结束时间Dispatcher.getBeginTime()+Dispatcher.getRunTime());this.addFinishProc(proc);this.executing = this.delPreProc();break; //时间片没用完,程序执行完,下一次调度}else{if(time<=0){ //时间片用完//当前执行进程放入就绪队列this.addPreProc(proc);//从就绪队列取下一个进程占用cputhis.executing = this.delPreProc();break;//时间片用完,程序未执行完,下一次调度}}}if(!this.prelst.isEmpty()){ //抢占Process preproc = this.prelst.get(0);if(this.executing.Priority>(preproc.Priority+1)){//取出时优先级已经降一级this.executing.setPriority(//恢复优先级,放入当前进程被取出队列尾部this.executing.Priority+1);this.addPreProc(this.executing);this.executing = this.delPreProc();break; //抢占,下一次调度}}}super.processWaitlst(proctimeslice);++Dispatcher.runTime;}}八、测试结果1.先来先服务➢申请资源及阻塞➢中间状态➢执行结果2.优先级➢按优先顺序放入就绪队列➢优先级抢占及执行结果3.时间片轮转➢测试数据➢中间过程➢测试结果4.多级反馈轮转➢测试数据➢抢占测试➢执行状态➢执行结果九、设计过程难点1.遇到的问题1)调度时机决策2)迭代器的破坏3)多级反馈队列兼容4)设备分配、释放5)外部统一接口,类型兼容、上转型对象6)进程的抢占2.解决方法1)设置进程相应状态(空转、结束、阻塞、时间片用完、抢断)2)修改循环嵌套层次,或标记迭代位置、跳出该层循环重构迭代器3)采用单一就绪队列,各进程转入就绪队列进行插入排序,插入相应位置4)扫描设备请求表,判断系统设备表中申请的设备是否空闲;扫描系统设备表,判断设备是否运转完毕,修改设备状态及进程状态5)为提供外部统一调用接口,采用类的继承及上转型对象,用同一调用实现不同算法;为实现类型兼容,采用抽象类及虚函数6)没执行一次,判断就绪队列首端元素是否有更高优先级,就绪队列插入元素直接进行插入排序,平均复杂度为O(n),实际上只需要常数级的比较和移动十、总结1.系统实现情况➢该系统实现了C++及Java两个版本➢Java版本实现了上述各调度算法,设备的自动分配及释放,有良好的用户操作接口、有很好的容错提示能力➢C++版本实现了上述调度算法、提供用户选择设备接口、MFC实现良好的操作界面➢采用纯面向对象的思想,有良好的封装性,接口统一➢用到了抽象类及虚函数、类型兼容、函数重载及运算符重载➢采用了泛化的变成思想,解决了迭代器的完整性问题➢逻辑与控制显示分离,算法与界面分离并使用不同的现成执行2.系统特点➢根据要求实现了各类调度算法,并实现了抢占和非抢占工作方式➢用户可在创建进程时发出多个设备请求➢程序自动检测设备请求,阻塞进程并在适当时机唤醒➢在插入队列是对进程排序预处理、减少执行过程中的比较次数3.收获➢掌握了进程调度的完整过程➢进一步复习了C++语言,加强了面向对象的思想,掌握了如何实现逻辑、控制、显示的分离➢复习了多线程的编程思想➢掌握了抽象类及虚函数的应用,学习了上转型对象的应用➢进一步学习泛化编程思想,掌握了如何保证迭代器的完整性➢进一步实践如何在面向对象工程中分工合作,采用逻辑分离的思想使得各个模块并行实现以及各模块的单元测试十一、参考文献1.著作:[1] 张尧学,史美林.计算机操作系统教程第2版.清华大学出版社2000年2.著作:[2] 张尧学.计算机操作系统教程第2版习题与实验指导. 清华大学出版。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程设计说明书题目: 并发进程的模拟院系:计算机科学与工程专业班级:学号:学生姓名:指导教师:2014年 11月 12 日安徽理工大学课程设计(论文)任务书2014年11月21日安徽理工大学课程设计(论文)成绩评定表I目录1问题描述 02需求分析 03概要设计 (1)1. P操作 (1)2. V操作 (2)3. P,V操作实现进程同步 (3)4. 功能模块设计 (4)4详细设计 (6)1.主界面的设计程序 (6)2.进程Pa的执行 (7)3.进程Pb的执行 (8)4.进程Pc的执行 (8)5.按钮的执行 (9)5 调试的分析与运行结果 (10)6 设计体会 (12)参考文献 (13)1问题描述在进程并发执行的过程中,进程之间存在协作的关系,例如,有互斥、同步的关系。

该课程设计的是了解进程同步的概念,理解信号量机制的原理,掌握运用信号量解决进程并发控制问题的方法,进而学会运用进程的同步,利用信号灯的P,V操作实现三个进程的同步。

这三个进程的同步关系如下:从上图中可以看出:任务启动后pa先执行,当它结束后,pb、pc可以开始执行,pb、pc 都执行完毕后,任务终止;设两个同步信号灯sb、sc分别表示进程pb和pc能否开始执行,其初值均为0。

在现代操作系统中,有大量的并发进程在活动,它们都处在不断的申请资源,使用资源以及其它进程的相互制约的活动中,这些进程什么时候停止运行,什么时候该继续向前推进,应根据事先的约定来规范它们的行为,这时我们可以根据同步信号灯来实现进程的同步协调工作。

例如本题中,只有pa进程顺利的进行完,Pb,Pc这两个进程才能正常的进行。

如果进程Pa在进行中出现停止或中断,则Pb和Pc是不会顺利的完成的;而进程Pb,Pc这两个进程是并行执行的,两个进程的进行是互不干扰的,只要进程Pa完成后,进程Pb和Pc才会正常执行,否则只有处在等待就绪中。

2需求分析进程执行的并发性的意义是关于一组进程的执行在是时间上是重叠的,从宏观上看,并发性反应的是一个时间段中几个进程都在同一个处理器上,处于运行还未运行结束状态。

从微观上看,任何一个时刻仅有一个进程在处理器上运行。

并发的实质是一个处理器在几个进程之间的多路复用,并发是对有限的物理资源强制行驶多用户共享,消除计算机部件之间的乎等现象,以提高系统资源利用率。

并发进程分为无关的和交往的,无关的并发进程是一组并发进程分别在不同的变量集合上操作,一个进程的执行与其他并发进程的进展无关。

引入进程是为了更好的解决实际中存在的竞态问题,进程同步的主要任务是对多个相关的进程在执行次序上进行协调,以便并发执行的诸进程之间能有效的共享资源和相互合作,从而使执行更具有可再现性。

利用进程同步可以更好地解决生活中有先后执行顺序的问题,进程的交往包括金正与写作,多个进程之间彼此相关或者是无关,二资源金正的两个控制问题一个是死锁(Deadlock)问题,一个是饥饿(Starvation)问题,系统中既要解决饥饿问题,又要解决死锁问题。

解决进程间的竞争关系(简介制约关系)的手段是进程互斥,进程互斥指的的就是资源的共享问题,以往内在同一时刻最多允许一个进程使用,其他进程必须等待,我们这个任务所需要的就是先执行其中的一个任务,在结束之后进行另外的进程。

所以我们解决这个问题的同时学习并发进程。

3概要设计1.P操作对信号灯的P操作记为P(s)。

P(s)是一个不可分割的原语操作,即取信号灯值减一,若相减结果为负,则调用P(s)的进程被阻,并插入到信号灯的等待队列中,否则可以继续执行。

P操作的主要动作:a)s值减一;b)若相减结果大于或等于0,则进程继续执行;c)若相减结果小于0,则进程被封锁,并将它插入到该信号灯的等待队列中,然后转进进程调度程序。

P操作的流程图:12.V操作对信号灯的V操作记为V(s)。

V(s)一个不可分割的原语操作,即取信号灯值加1,若相加结果大于0,进程继续执行,否则,唤醒在信号灯等待队列上的一个进程。

V操作的主要动作a)s值加一;b)若相减结果大于0,则进程继续执行;c)若相减结果小于或等于0,则从该信号灯的等待队列中移出一个进程,解除它的等待状态,然后返回本进程继续执行。

V操作的流程图:3.P,V操作实现进程同步(1)编程用信号灯的p、v操作实现这三个进程的同步。

(2)任务启动后pa先执行,当它结束后,pb、pc可以开始执行,pb、pc 都执行完毕后,任务终止。

(3)设两个同步信号灯sb、sc分别表示进程pb和pc能否开始执行,其初值均为0。

其题目的算法描述如下:34.功能模块设计本实验用JAVA语言实现(1)在Frame工程中新建一个ThreadProcess类,定义一些静态变量;主函数main()中定义一个ThreadFrame类,并构造一个对象thFrame,通过调用函数将界面,窗口展示出来;创建三个线程threadPa, threadPb, threadPc。

(2)ThreadFrame类继承JFrame类,设置每个界面的长宽,调用类方法ThreadFrame()显示一些信息。

(3)threadPanel类继承JPanel类,调用paintComponent()方法设置进程长宽以及字体等,还有threadPanel()类方法设置进程前景与背景颜色,从而展示出进程动态变化,重要一点是开始Start和暂停Stop按钮设置,控制进程开始与暂停效果。

(4)在类外分别添加三个进程类threadPa, threadPb, threadPc,都继承线程Thread类,其中各自有的控制函数run()。

程序执行能够达到实验的要求效果,程序运行后,点击Start按钮进程执行,首先进程Pa先执行,Pa结束后进程Pb和进程Pc启动开始执行,而且能够达到系统资源共享的效果,最后所有结束后告知程序结束。

如果一开始点击Stop按钮,那么进程没响应,等待点击Start按钮,这是并发进程的模拟过程并发进程的模拟中定义四个模块,实现界面进程运行过程。

程序执行能够达到实验的要求效果,程序运行后,点击Start按钮进程执行,首先进程Pa先执行,Pa结束后进程Pb和进程Pc启动开始执行,而且能够达到系统资源共享的效果,最后所有结束后告知程序结束。

并发进程的模拟功能模块流程图如图5所示。

54详细设计1.主界面的设计程序class ThreadFrame extends JFrame {public int WIDTH = 820;public int HEIGHT = 500;public threadPanel threadPanel = new threadPanel();public Container container;public ThreadFrame() {this.setTitle("模拟进程并发的过程图");this.setSize(WIDTH, HEIGHT);this.setLocation(250, 150);this.setResizable(false);container = getContentPane();container.add(threadPanel);setVisible(true);}}2.进程Pa的执行class threadPa extends Thread {public static boolean flag = true;// JProgressBar progressBar;private static int i = 0;/** public threadPa(JProgressBar progressBar) { ThreadProcess.progressBar1 = * progressBar; }*/@Overridepublic void run() {ThreadProcess.sb--;ThreadProcess.sc--;while (i <= 100) {i += 1;ThreadProcess.progressBar1.setValue(i);//System.out.println(i);try {Thread.sleep(30);// threadPa.interrupted();} catch (InterruptedException e) {e.printStackTrace();}}ThreadProcess.sb++;ThreadProcess.sc++;if (ThreadProcess.sb >= 0 && ThreadProcess.sc >= 0 ) {ThreadProcess.threadPb.start();ThreadProcess.threadPc.start();}//System.out.println(ThreadProcess.progressBar1.getValue());//System.out.println(ThreadProcess.sb);}}73.进程Pb的执行class threadPb extends Thread {public static boolean flag = true;// JProgressBar progressBar;private static int i = 0;/** public threadPb(JProgressBar progressBar) { this.progressBar =* progressBar; }*/@Overridepublic void run() {while (i <= 100) {i += 1;ThreadProcess.progressBar2.setValue(i);try {Thread.currentThread().sleep(30);} catch (InterruptedException e) {e.printStackTrace();}}}}4.进程Pc的执行class threadPc extends Thread {public static boolean flag = true;// JProgressBar progressBar;private static int i = 0;/** public threadPc(JProgressBar progressBar) { this.progressBar =* progressBar; }*/@Overridepublic void run() {while (i <= 100) {i += 1;ThreadProcess.progressBar3.setValue(i);try {Thread.currentThread().sleep(30);} catch (InterruptedException e) {e.printStackTrace();}}}5.按钮的执行public threadPanel() {setLayout(null);// 设置边框按钮的起始左上点的坐标setSize(800, 400);ThreadProcess.progressBar1 = new JProgressBar();ThreadProcess.progressBar2 = new JProgressBar();ThreadProcess.progressBar3 = new JProgressBar();// 设置start与stop按钮buttonstart1 = new JButton("Start");buttonstop1 = new JButton("Stop");ThreadProcess.progressBar1.setBackground(new Color(255, 50, 255));ThreadProcess.progressBar1.setForeground(new Color(10, 90, 90));ThreadProcess.progressBar1.setBounds(100, 70, 480, 40);buttonstart1.setBounds(600, 10, 80, 40);buttonstop1.setBounds(700, 10, 80, 40);add(ThreadProcess.progressBar1);add(buttonstart1);add(buttonstop1);buttonstart1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent arg0) {// ThreadProcess.pa();ThreadProcess.threadPa.start();/*try {ThreadProcess.threadPa.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}*///System.out.println(ThreadProcess.sb+"kl");/*boolean t1=ThreadProcess.threadPa.isAlive();int t2=ThreadProcess.sb;int t3=ThreadProcess.sc;int t4=ThreadProcess.progressBar1.getValue();*//*System.out.println(t1);System.out.println(t2);System.out.println(t3);*///System.out.println(ThreadProcess.temp);//if(!ThreadProcess.threadPa.isAlive()) ;9//}// threadPa.flag = true;}});buttonstop1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent arg0) {threadPa.flag = false;}});ThreadProcess.progressBar2.setBackground(new Color(255, 90, 100));ThreadProcess.progressBar2.setForeground(new Color(90, 50, 90));ThreadProcess.progressBar2.setBounds(100, 190, 480, 40);add(ThreadProcess.progressBar2);ThreadProcess.progressBar3.setBackground(new Color(100, 100, 255));ThreadProcess.progressBar3.setForeground(new Color(100, 90, 90));ThreadProcess.progressBar3.setBounds(100, 300, 480, 40);add(ThreadProcess.progressBar3);}}5 调试的分析与运行结果1.初次运行程序界面运行并发进程模拟程序出现初次界面,如图6所示。

相关文档
最新文档