• 进程调度基本方法及实现


       进程的四大特点: 并发、共享、虚拟、异步。

       进程调度便是实现并发的关键一环。

       在操作系统中存在多种调度算法,其中有的调度算法适用于作业调度,有的调度算法适用于进程调度,有的调度算法两者都适用。

      1.先来先服务(FCFS)

      一种简单的调度算法,适用于作业和进程调度。先来先服务算法按照进程/作业到达先后顺序来进行调度。当作业调度采用该算法时,每次调度都会从后备队列中取出最先到达的作业,为他分配内存,创建PCB,放入就绪队列中;当进程调度采用该算法时,每次调度都会从就绪队列中取出最先进入该队列的进程,给他分配处理机(处理机=CPU+主存储器+IO设备)。

      2.短作业优先(SJF)

      作业或进程的长短是以作业或进程要求运行时间的长短来衡量的。

           3.优先级调度

      作业或进程的优先级来确定优先调度权。

      (1)静态优先级  --- 优先级在进程/作业调度前就确定并不会更改。

      (2)动态优先级 --- 优先级会随进程的执行情况而改变,更灵活,科学。

      4.时间片轮转法(RR)

      主要用于分时系统的进程调度进程/作业放在一个队列上,CPU拿出第一个进程运行一个时间片后,将其放在队尾,轮询执行。

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<string.h>
    #include <algorithm>  
    using namespace std;
    
    int choice;  //选项
    int n;       //进程数  
    
    bool ok[100] = {0};    //作业完成情况 1为完成 0为未完成
    int last[100] = { 0 };  //任务剩余时间 
    
    struct pcb{
    	int pid;   //进程号
    	int atime;   //到达时间
    	int rtime;   //运行时间
    	int stime;   //开始时间
    	int etime;   //结束时间
    	int time;    //周转时间
    	float dtime;   //带权周转时间
    	int priority;  //优先级
    	int timechip; //时间片
    }pro[100];  //最大进程数组,输入输出参数
    
    
    //先来先服务算法进程排序规则, 先按照到达时间升序,再按照进程号升序排列  
    bool fcfscmp(pcb a,pcb  b) {
    	if (a.atime != b.atime)return a.atime < b.atime;
    	return a.pid < b.pid;
    }
    
    //动态优先级算法进程排序规则,先按照进程优先数升序,再按到达时间升序,再按进程号升序排列  
    bool pricmp(pcb a, pcb b) {
    	if (a.priority != b.priority)return a.priority < b.priority;
    	if (a.atime != b.atime)return a.atime < b.atime;
    	return a.pid < b.pid;
    }
    
    //先来先服务
    void FCFS()
    {
    	int t = 0;
    	int dt = 0;
    	//排序到达时间最早的作业
    	sort(pro + 1, pro + 1 + n, fcfscmp);
    	//依次完成作业
    	printf("
    ==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====
    ");
    	for (int i = 1; i <= n; i++) {   
    
    		pro[i].stime = max(t, pro[i].atime);//开始时间 = max(系统时间,到达时间)
    		pro[i].etime = pro[i].stime + pro[i].rtime;
    		pro[i].time = pro[i].etime - pro[i].atime; //周转时间 = 结束 - 到达
    	    pro[i].dtime = pro[i].time/pro[i].rtime; //带权周转时间 = 周转时间/运行时间
    
    		//总周转时间,总带权周转时间
    		t += pro[i].time;
    		dt += pro[i].dtime;
    		
    		printf("      %d     %d        %d         %d       %d        %d          %3.3f
    ",
    			pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime,pro[i].etime,pro[i].time,pro[i].dtime);
    	}
    	float avet = (float)t / n;
    	float avedt = (float)dt / n;
    	printf("平均周转时间为%3.3f,平均带权周转时间为%3.3f
    ",avet,avedt);
    	
    }
    
    //短作业优先
    void SPF()
    {
    	//作业完成情况先置0
    	memset(ok, 0, sizeof(ok));
    	int t = 0;
    	int dt = 0;
    	int min = 1;
    	printf("
    ==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====
    ");
    	for (int i = 1; i <= n; i++) {
    
    		//1.找出当前最短时间作业
    		int flag = 0;  //标记是否有到达作业
    		while (flag == 0){
    			for (int j = 1; j <= n; j++) {
    				if (ok[j] == 1)continue; //已经运行完成的进程  
    				if (pro[j].atime > t)continue; //没有到达的进程  
    				//出现一个已到达进程
    				if (pro[j].atime <= t && flag == 0) {
    					min = j;
    					flag = 1;
    				}
    				//出现两个已到达进程,比较出最短时间进程
    				else if (pro[j].atime <= t && flag == 1) {
    					if ((pro[j].rtime < pro[min].rtime) || (pro[j].rtime == pro[min].rtime&&pro[j].pid < pro[min].pid)) {
    						//运行时间短的进程优先                     运行时间相同时,按顺序  
    						min = j;
    					}
    				}
    			}// end of for
    
    			//此时,没有进程到达,时间+1
    			if (flag == 0) t++;
    		}
    
    		//2.完成作业
    		pro[i].stime = max(t, pro[min].atime);
    		pro[i].etime = pro[i].stime + pro[min].rtime;
    		pro[i].time = pro[i].etime - pro[i].atime; //周转时间 = 结束 - 到达
    		pro[i].dtime = pro[i].time / pro[i].rtime; //带权周转时间 = 周转时间/运行时间
    
    		//总周转时间,总带权周转时间
    		t += pro[i].time;
    		dt += pro[i].dtime;
    
    		printf("      %d     %d        %d         %d       %d        %d          %3.3f
    ",
    			pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime);
    
    		ok[min] = 1;  //标记这个进程完成
    	}
    	float avet = (float)t / n;
    	float avedt = (float)dt / n;
    	printf("平均周转时间为%3.3f,平均带权周转时间为%3.3f
    ", avet, avedt);
    
    }
    
    /*判断是否全部进程都执行完毕*/
    int charge()
    {
    	for (int i = 1; i<=n; i++)
    	{
    		if (last[i] != 0)
    			return 1;
    	}
    	return 0;
    }
    //轮转法
    void RR() {
    	//作业完成数组置0
    	memset(ok, 0, sizeof(ok));
    	int t = 0 , dt = 0;
    	sort(pro + 1, pro + n + 1, fcfscmp);//排序:先来先服务原则  --- 有利于后面轮询
    	
    	int i = 0;
    	//*关键 : 记录进程剩余时间
    	for (int i = 1; i <= n; i++)
    	{
    		last[i] = pro[i].rtime;
    	}
    	int chip = pro[1].timechip; //时间片
    	int time = pro[1].atime;      //当前时间的初值 
    	
    	//按顺序轮询,就绪态运行,阻塞态等待到达时间
    	printf("
    ==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====
    ");
    	while (charge()) //能进charge说明还有进程
    	{
    		int flag = 0; //标记是否还有就绪任务
    		for (i = 1; i <= n; i++)    //时间片轮转法执行各进程 
    		{
    			if (ok[i] == 1)
    				continue;  //已完成的进程 
    				
    				//就绪进程轮转
    				if (last[i]<=chip && time>=pro[i].atime)//未完成的进程但是还需服务的时间少于等于一个时间片 
    				{
    					flag = 1;
    					//记录第一次开始运行时间
    					if (pro[i].rtime == last[i]) 
    						pro[i].stime = time; //开始时间 = 当前时间
    
    					//时间更新,任务完成
    					time += chip;
    					last[i] = 0;
    					ok[i] = 1;
    	
    					pro[i].etime = time; //结束时间
    					pro[i].time = pro[i].etime - pro[i].atime; //周转时间 = 结束 - 到达
    					pro[i].dtime = pro[i].time / pro[i].rtime; //带权周转时间 = 周转时间/运行时间
    
    					//总周转时间,总带权周转时间
    					t += pro[i].time;
    					dt += pro[i].dtime;
    
    					printf("      %d     %d        %d         %d       %d        %d          %3.3f
    ",
    						pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime);
    						
    				}
    				else if (last[i]>chip && time>=pro[i].atime)//未完成的进程但其还需服务时间至少大于一个时间片 
    				{
    					flag = 1;
    					//记录第一次开始运行时间
    					if (last[i]==pro[i].rtime)
    						pro[i].stime = time; //开始时间 = 当前时间
    
    					time += chip;
    					last[i] -= chip;
    					
    				}
    		}//end of for
    
    		//没有一个就绪进程,自增时间
    		if (flag == 0)
    		{
    			time += chip;
    		}
    	}//end of while
    	float avet = (float)t / n;
    	float avedt = (float)dt / n;
    	printf("平均周转时间为%3.3f,平均带权周转时间为%3.3f
    ", avet, avedt);
    
    }
    
    //优先级调度
    void PRI() {
    	//作业完成数组置0
    	memset(ok, 0, sizeof(ok));
    	int t = 0, dt = 0;
    	sort(pro + 1, pro + n + 1, pricmp);//排序:优先级
    
    	int i = 0;
    	//*关键 : 记录进程剩余时间
    	for (int i = 1; i <= n; i++)
    	{
    		last[i] = pro[i].rtime;
    	}
    	int chip = pro[1].timechip; //时间片
    	int time = pro[1].atime;      //当前时间的初值 
    	
    	//按优先级顺序轮询,轮询完再次优先级排序
    	printf("
    ==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====
    ");
    	while (charge()) //能进charge说明还有进程
    	{
    		int flag = 0; //标记是否还有就绪任务
    		for (i = 1; i <= n; i++)    //时间片轮转法执行各进程 
    		{
    			if (ok[i] == 1)
    				continue;  //已完成的进程 
    
    			//就绪进程轮转
    			if (last[i] <= chip && time >= pro[i].atime)//未完成的进程但是还需服务的时间少于等于一个时间片 
    			{
    				flag = 1;
    				//记录第一次开始运行时间
    				if (pro[i].rtime == last[i])
    					pro[i].stime = time; //开始时间 = 当前时间
    
    				//时间更新,任务完成
    				time += chip;
    				last[i] = 0;
    				ok[i] = 1;
    
    				pro[i].etime = time; //结束时间
    				pro[i].time = pro[i].etime - pro[i].atime; //周转时间 = 结束 - 到达
    				pro[i].dtime = pro[i].time / pro[i].rtime; //带权周转时间 = 周转时间/运行时间
    
    				//总周转时间,总带权周转时间
    				t += pro[i].time;
    				dt += pro[i].dtime;
    
    				printf("      %d     %d        %d         %d       %d        %d          %3.3f
    ",
    					pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime);
    
    			}
    			else if (last[i]>chip && time >= pro[i].atime)//未完成的进程但其还需服务时间至少大于一个时间片 
    			{
    				flag = 1;
    				//记录第一次开始运行时间
    				if (last[i] == pro[i].rtime)
    					pro[i].stime = time; //开始时间 = 当前时间
    
    				time += chip;
    				last[i] -= chip;
    				pro[i].priority -= 1;  //如果没完成,优先级-1
    			}
    		}//end of for
    
    		sort(pro + 1, pro + n + 1, pricmp);//排序:优先级
    		//没有一个就绪进程,自增时间
    		if (flag == 0)
    		{
    			time += chip;
    		}
    	}//end of while
    	float avet = (float)t / n;
    	float avedt = (float)dt / n;
    	printf("平均周转时间为%3.3f,平均带权周转时间为%3.3f
    ", avet, avedt);
    
    }
    
    //输入界面
    void Menu()
    {
    	while (1){
    		n = 0;
    		choice = 0;
    		printf("=== 请选择算法: ===
    *   1.先来先服务   *
    *   2.短作业优先   *
    *   3.时间片轮转   *
    *   4.优先级调度   *
    *   0.退出         *
    选择:");
    		scanf("%d", &choice);
    		if (choice == 0) 
    			return;
    		printf("请选择进程数:");
    		scanf("%d", &n);
    		printf("***            请依次写入           ***
     PID 到达时间 运行时间 优先级 时间片大小:
    ");
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d %d %d %d %d", &pro[i].pid, &pro[i].atime, &pro[i].rtime, &pro[i].priority, &pro[i].timechip);
    		}
    		if (n == 0)
    			return;
    		switch (choice) {
    		case 1:FCFS(); break;//先来先服务调度算法  
    		case 2:SPF(); break;//短作业优先调度算法  
    		case 3:RR(); break;//时间片轮转调度算法  
    		case 4:PRI(); break;//优先级调度算法  
    		}
    		printf("
    ");
    	}
    }
    
    int main()
    {
    	Menu();
    	return 0;
    }
    

      

  • 相关阅读:
    VMware虚拟机中常见的问题汇总
    Windows10下安装VMware虚拟机并搭建CentOS系统环境
    myeclipse2017使用总结
    mybatis如何通过接口查找对应的mapper.xml及方法执行详解
    (转)将SVN从一台服务器迁移到另一台服务器(Windows Server VisualSVN Server)
    (转)Maven中的库(repository)详解 ---repository配置查找构件(如.jar)的远程库
    Git知识讲解
    (转)MyEclipse中使用git
    在SpringBoot中添加Logback日志处理
    (转)Spring Boot干货系列:(七)默认日志logback配置解析
  • 原文地址:https://www.cnblogs.com/Duikerdd/p/11963579.html
Copyright © 2020-2023  润新知