四种算法
- 先来先服务算法
先来先服务调度算法是按照作业到达的先后次序进行调度,或者说是有优先考虑在系统中等待时间最长的作业,而不管该作业所需执行时间的长短,从后背作业队列中选择几个最先进入系统的作业,将他们调入内存,为它们分配资源和创建进程,然后将它放入就绪队列。每次进程调度就从酒席队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行,该进程一直运行到完成或发生某事件而阻塞后,进程调度程序才将处理及分配给其他进程。 - 短作业优先算法
短作业优先调度算法是以作业的长短来计算优先级,作业越短,其优先级越高。作业的长短是以作业要求的运行时间来衡量的。 - 时间片轮转调度算法
时间片轮转调度算法是基于时间片的轮转而形成的算法。让就绪队列上的每个进程每次进运行一个时间片。如果就绪队列有n个进程,则每个进程每次大约都可获得1/n的处理机时间。在轮转中,系统会根据先来先服务调度算法的策略将所有进程的就绪锦成排成一个就绪队列,并设置每隔一定时间间隔产生一次中断,激活系统中的进程调度程序,完成一次调度,将处理机分配给队首进程,令其执行。当该进程的时间片耗尽或运行完毕后,系统再次将处理机给新的队首进程,这样可以保证就绪队列中的所有进程在一个确定的时间段内,都能获得一次处理机执行。 - 优先级算法
高响应比优先级调度算法是为每个作业动态的引入优先级,及优先级是可以变化的,令它随等待时间延长而增加,这就是厂作业的优先级在等待期间不断的增加,等到足够的时间后,必然有机会获得处理机(优先权=(等待时间=+要求服务时间)/ 要求服务时间)。
源代码
github链接: link.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define Process_MAX 10
//建立两个结构体
//第一个结构体,单个进程的信息
typedef struct Process{
int rank;//执行的次序
int name;
int arrive;
int run;
int start;
int finish;
int turnaround;
int wait;
double weight_turnaround;
//标志位
int flag;
}Process;
//第二个结构体,整个进程表
typedef struct ProccessTable{
//进程数组
Process process[Process_MAX];
//平均周转时间
double average_turnaround;
//平均等待时间
double average_wait;
//平均带权周转时间
double average_weight_turnaround;
//有效进程数
int size;
}ProcessTable;
//初始化
void initProcessTable(ProcessTable* processTable){
printf("请输入进程的总数:");
scanf("%d",&processTable->size);
//初始化到达时间和估计运行时间
for (int i = 0; i < processTable->size; i++){
printf("请输入第%d进程的名称,到达时间和估计运行时间:", i + 1);
scanf("%d %d %d", &processTable->process[i].name,
& processTable->process[i].arrive, &processTable->process[i].run);
}
}
//返回基于短作业优先算法中当前需执行的进程(不要进行排序,否则会覆盖数据,导致数据丢失)
int SJFSort(ProcessTable* processTable,int executionProcess,int nowTime){
//该数组用于存放当前已经到达内存的进程 (此处存放的不是下标,因为初始化为0,易混淆)
int nowArriveProcess[Process_MAX] = { 0 };
//记录该数组的有效存储的进程个数
int count = 0;
//step1. 找出当前时间已经到达内存却未被CPU执行的进程
for (int i = 0; i < processTable->size; i++){
if (processTable->process[i].flag!=1
&&processTable->process[i].run <= nowTime){
nowArriveProcess[count++] = i+1;
}
}
//step2. 找出这些进程谁的作业最短的进程的下标
executionProcess = nowArriveProcess[0] - 1;
for (int i = 1; i < count; i++){
if (processTable->process[nowArriveProcess[i] - 1].run>processTable->process[executionProcess].run){
//将作业较短的进程下标存入将要执行的变量中
executionProcess = nowArriveProcess[i - 1] - 1;
}
else{
executionProcess = nowArriveProcess[i] - 1;
}
}
return executionProcess;
}
void compute(ProcessTable* processTable){
Process* p = processTable->process;
//step1. 计算周转时间, 等待时间, 带权周转时间
processTable->average_turnaround = 0.0;
processTable->average_weight_turnaround = 0.0;
processTable->average_wait = 0.0;
for (int i = 0; i < processTable->size; i++){
//周转时间=完成时间-开始时间
p[i].turnaround = p[i].finish - p[i].arrive;
processTable->average_turnaround += (double)p[i].turnaround;
//等待时间=周转时间-运行时间
p[i].wait = processTable->process[i].turnaround - p[i].run;
processTable->average_wait += (double)processTable->process[i].wait;
//带权周转时间=周转时间 / 运行时间
p[i].weight_turnaround = (double)p[i].turnaround / (double)p[i].run;
processTable->average_weight_turnaround += (double)p[i].weight_turnaround;
}
//step2. 计算平均周转时间,平均等待时间, 平均带权周转时间
//平均周转时间
processTable->average_turnaround = processTable->average_turnaround / (double)processTable->size;
//平均等待时间
processTable->average_wait = processTable->average_wait / (double)processTable->size;
//平均带权周转时间
processTable->average_weight_turnaround = (double)processTable->average_weight_turnaround / (double)processTable->size;
}
//打印进程的信息
void printProcessTable(ProcessTable* processTable){
printf(" 进程信息\n");
printf("===========================================================================================\n");
printf("Num\tSeq\tName\tArrive\tRun\tStart\tFinish\tTAround\tWait\tWTAround\n");
for (int i = 0; i < processTable->size; i++){
printf("[%d]\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\t %3.2f\n", i + 1,
processTable->process[i].rank, processTable->process[i].name,
processTable->process[i].arrive,processTable->process[i].run,
processTable->process[i].start,processTable->process[i].finish,
processTable->process[i].turnaround, processTable->process[i].wait,
processTable->process[i].weight_turnaround);
}
printf("平均周转时间: %3.2f\n", processTable->average_turnaround);
printf("平均等待时间: %3.2f\n", processTable->average_wait);
printf("平均带权周转时间为:%3.2f\n", processTable->average_weight_turnaround);
printf("===========================================================================================\n");
}
//进程调度算法
//1. 先来先服务算法
void FCFS(ProcessTable* processTable){
Process* p = processTable->process;
//冒泡排序
for (int bound = 0; bound < processTable->size-1; bound++){
for (int cur = processTable->size - 1; cur>0; cur--){
if (p[cur].arrive < p[cur - 1].arrive){
Process temp = p[cur];
p[cur] = p[cur - 1];
p[cur - 1] = temp;
}
}
}
//计算开始时间和完成时间
//第一个进程
p[0].start = p[0].arrive;
//完成时间=开始时间+运行时间
p[0].finish = p[0].start + p[0].run;
//后续进程
for (int i = 1; i < processTable->size; i++){
//如果该进程在来临时,上一个进程尚未结束或刚刚结束
if (p[i - 1].finish >= processTable->process[i].arrive){
p[i].start = p[i - 1].finish;
p[i].finish = p[i].start + p[i].run;
}
else{
p[i].start = p[i].arrive;
p[i].finish = p[i].start + p[i].run;
}
}
compute(processTable);
printProcessTable(processTable);
}
//2. 短作业优先算法
//核心思路: 先从时间上考虑,从哪个进程开始,下一进程使用最短作业优先
void SJF(ProcessTable* processTable){
int count = 1;
int priorExecutionProcess = 0;
int executionProcess = 0;
Process* p = processTable->process;
//第一个进程,找到最早开始且运行时间最短的进程的数组下标
//executionProcess = SJFSort(processTable, executionProcess, 0);
for (int cur = processTable->size - 1; cur>0; cur--){
//step1 先找最早开始的
if (p[cur].arrive < p[cur - 1].arrive){
executionProcess = cur;
}else if (p[cur].arrive > p[cur - 1].arrive){
executionProcess = cur - 1;
}else{
//进入内存时间相同
//step2 再找运行时间最短的 (即短作业)
if (p[cur].run > p[cur - 1].run){
executionProcess = cur - 1;
}
else{
executionProcess = cur;
}
}
}
p[executionProcess].rank = count;
p[executionProcess].start = p[executionProcess].arrive;
p[executionProcess].finish = p[executionProcess].start + p[executionProcess].run;
p[executionProcess].flag = 1;
priorExecutionProcess = executionProcess;
//后续进程
while (count<=processTable->size){
//取出当前已到达的的进程且运行时间最短的进程
executionProcess = SJFSort(processTable, executionProcess, p[priorExecutionProcess].finish);
p[executionProcess].rank = count+1;
p[executionProcess].start = p[priorExecutionProcess].finish;
p[executionProcess].finish = p[executionProcess].start + p[executionProcess].run;
p[executionProcess].flag = 1;
count++;
priorExecutionProcess = executionProcess;
}
compute(processTable);
printProcessTable(processTable);
}
//3. 时间片轮转调度算法
void RR(ProcessTable* processTable){
compute(processTable);
printProcessTable(processTable);
}
//4.高响应比优先级调度算法
void HRRN(ProcessTable* processTable){
compute(processTable);
printProcessTable(processTable);
}
int menu(){
int choice;
while (1){
printf("=================================\n");
printf("1.先来先服务算法\n");
printf("2.短作业优先算法\n");
printf("3.时间片轮转调度算法\n");
printf("4.高响应比优先级调度算法\n");
printf("=================================\n");
printf("请输入您的选择:");
scanf("%d", &choice);
if (choice > 4 || choice < 1){
continue;
}
break;
}
return choice;
}
ProcessTable processTable;
int main()
{
initProcessTable(&processTable);
int choice = menu();
if (choice == 1){
FCFS(&processTable);
}else if(choice == 2){
SJF(&processTable);
}else if (choice == 3){
RR(&processTable);
}else if (choice == 4) {
HRRN(&processTable);
}else{
printf("您输入有误\n");
}
system("pause");
return 0;
}
运行结果
/*
请输入进程的总数:4
请输入第1进程的名称,到达时间和估计运行时间:1 0 7
请输入第2进程的名称,到达时间和估计运行时间:2 2 4
请输入第3进程的名称,到达时间和估计运行时间:3 4 1
请输入第4进程的名称,到达时间和估计运行时间:4 5 4
进程信息
===========================================================================================
Num Seq Name Arrive Run Start Finish TAround Wait WTAround
[1] 1 1 0 7 0 7 7 0 1.00
[2] 4 2 2 4 12 16 14 10 3.50
[3] 2 3 4 1 7 8 4 3 4.00
[4] 3 4 5 4 8 12 7 3 1.75
平均周转时间: 8.00
平均带权周转时间为:2.56
===========================================================================================
请按任意键继续. . .
*/
总结
通过这次实验,我采用了四种进程调度算法对进程进行调度,把课本上的理论知识转化为实践,在一定程度上加深了我对先来先服务调度算法、短作业优先调度算法、时间片轮转调度算法以及高响应比优先级调度算法的理解,同时提高了我的动手编程能力。肃然在编程的过程中,遇到了很多的问题。但是我掌握了了很多东西,我掌握了先来先服务调度算法,掌握了程序控制块的定义,也掌握了对就绪队列,完成队列中节点的选择和插入。操作系统中的一个核心的问题就是进程调度问题。对于不同的作业条件,情况,特点,都有不同的需求和特性。所以采用合理的有针对性的进程调度算法至关重要。采用正确的进程调度算法,不仅可以让多个进程并发的执行,而且还可以最大化的利用处理机的工作时间,这样高效率的调度策略使得计算机很良好的协调各个进程或作业之间的调度,从而使得计算机的运行速度有了极大的提高。
此外,我也对用本次使用的编程语言有了深刻的理解,希望在以后的实验中做得更好。在将来的学习中,我将继续努力加深理解操作系统的基本原理,了解计算机是如何工作的。计算机操作系统中有了很多知识,我想我们可以从这门课中学习到东西,它使我们了解其他计算机知识的基础,可以应用到学习其他计算机相关的课程中,帮助我们更好的学习有关计算机的课程。