这是操作系统课程的一次综合实验,模拟各种调度算法。
参考先来先服务算法,尝试实现其他四种调度算法:短作业优先、高响应比、时间片轮转、多级反馈队列。要求至少实现一种算法。
例题一:在单处理机环境下,对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,对应时间片为2、4、8。现有四个进程A、B、C、D,到达时刻分别为0、5、7、12,执行时间分别为7、4、13、9。请写出整个进程调度过程。
编写其他调度算法:
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;
}
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
#include
#include
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';
}
}
}
}
多级反馈队列算法基于时间片算法可以比较简单的实现,不同的是要维护三个队列,且每个队列优先级不同
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;
}
}
}
}
}
}