进程调度基本方法及实现

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

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

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

  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("\n==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====\n");
	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\n",
			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\n",avet,avedt);
	
}

//短作业优先
void SPF()
{
	//作业完成情况先置0
	memset(ok, 0, sizeof(ok));
	int t = 0;
	int dt = 0;
	int min = 1;
	printf("\n==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====\n");
	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\n",
			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\n", 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("\n==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====\n");
	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\n",
						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\n", 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("\n==== PID 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间 ====\n");
	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\n",
					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\n", avet, avedt);

}

//输入界面
void Menu()
{
	while (1){
		n = 0;
		choice = 0;
		printf("=== 请选择算法: ===\n*   1.先来先服务   *\n*   2.短作业优先   *\n*   3.时间片轮转   *\n*   4.优先级调度   *\n*   0.退出         *\n选择:");
		scanf("%d", &choice);
		if (choice == 0) 
			return;
		printf("请选择进程数:");
		scanf("%d", &n);
		printf("***            请依次写入           ***\n PID 到达时间 运行时间 优先级 时间片大小:\n");
		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("\n");
	}
}

int main()
{
	Menu();
	return 0;
}

  

posted @ 2019-12-16 18:27  Duikerdd  阅读(2301)  评论(0编辑  收藏  举报