**RR算法主要体现在两个时机的调度:
1.进程的服务时间用完时,无论时间片到没到,时间片都需要置0。
2.进程的服务时间没用完,而且时间片到了,需要把此进程添加到队尾,时间片置0。
进程都运行结束时,调出循环的条件需要注意。
具体可以看注释:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct PCB
{
char name;
int arrivaltime; //到达时间
int Servicetime; //服务时间
int Finishtime; //完成时间
int Wholetime; //周转时间
double WeightWholetime; //带权周转时间
}RR;
struct QueueNode { //链表结构
RR node;
struct QueueNode* next;
};
typedef struct { //队列结构
QueueNode* front; //队头
QueueNode* rear; //队尾
}LinkQueue;
void start_state(RR* ResultPCB,int n); //读入假设的数据,设置系统初始状态
void dispath(LinkQueue* q_ready,RR* ResultPCB,int n); // 模拟调度
void frontNodeTorear(LinkQueue* q); //队首进程添到队尾
bool IsEmptyQueue(LinkQueue* q); //队列判空
void InitQueue(LinkQueue* q); //分配内存
void InsertQueueNode(LinkQueue* q, RR TempPCB); //入队
bool DeleteQueueNode(LinkQueue* q); //出队
bool cmp(RR a,RR b); //排序辅助函数
int main()
{
LinkQueue* q_ready = (LinkQueue*)malloc(sizeof(LinkQueue)); //为就绪队列分配内存空间
InitQueue(q_ready);
int n; //进程个数
printf("Enter n:");
scanf("%d", &n);
RR* ResultPCB = (RR*)malloc(sizeof(RR)); //存储进程信息的结构体数组
start_state(ResultPCB, n); //进程初始化
dispath(q_ready, ResultPCB, n); //调度
//RR算法基本实现,下面进行数据汇总处理
int SumWT = 0;
double SumWWT = 0;
printf("\nID\tArrivalTime\tServiceTime\tFinishTime\tWholeTime\tWeightWholeTime\n");
for (int i = 0;i < n;i++) {
ResultPCB[i].Wholetime = ResultPCB[i].Finishtime - ResultPCB[i].arrivaltime;
ResultPCB[i].WeightWholetime = (1.0)*ResultPCB[i].Wholetime /ResultPCB[i].Servicetime;
SumWT += ResultPCB[i].Wholetime; //累计总周转时间
SumWWT += ResultPCB[i].WeightWholetime; //累计总带权周转时间
printf("%c\t\t%d\t\t%d\t\t%d\t\t%d\t\t%.2lf\n",ResultPCB[i].name, ResultPCB[i].arrivaltime, ResultPCB[i].Servicetime, ResultPCB[i].Finishtime, ResultPCB[i].Wholetime, ResultPCB[i].WeightWholetime);
}
double AverageWT = (1.0*SumWT) / n; //平均周转时间
double AverageWWT= (1.0 * SumWWT) / n;//平均带权周转时间
printf("SumWT=%d\n", SumWT);
printf("SumWWT=%.2lf\n", SumWWT);
printf("AverageWT=%.2lf\n", AverageWT);
printf("AverageWWT=%.2lf\n", AverageWWT);
return 0;
}
void start_state(RR* ResultPCB, int n) //初始化
{
for (int i = 0;i < n;i++){
ResultPCB[i].name = 'A' + i;
}
printf("Enter ArrivalTime:");
for (int i = 0;i < n;i++) {
scanf("%d", &ResultPCB[i].arrivaltime);
}
printf("Enter ServiceTime:");
for (int i = 0;i < n;i++) {
scanf("%d", &ResultPCB[i].Servicetime);
}
sort(ResultPCB, ResultPCB + n, cmp); //排序
}
void dispath(LinkQueue* q_ready, RR* ResultPCB, int n) //主要轮转算法实现
{
int j = 0; //累计入队的进程个数
int SumoperateTime = 0; //总时间
int x = 0; //累计时间片
int t; //时间片大小
printf("Enter TimeSlice:");
scanf("%d", &t);
while(1)
{
if (j >= n && !q_ready->front->next)
{
//当进入队列的进程个数为总进程数n时且队列为空时退出循环
//表示所有进程全部运行结束
break;
}
printf("Time%d:", SumoperateTime);
for (int i = 0;i < n;i++)
{
if (ResultPCB[i].arrivaltime == SumoperateTime)
{//每次需要遍历所有进程到达时间,可能有些进程到达时间一样,依次入队
printf(" %c arrived ", ResultPCB[i].name);
InsertQueueNode(q_ready, ResultPCB[i]); //添加新进程进入队列
++j; //入队的进程个数
}
}
if (0==q_ready->front->next->node.Servicetime) //队首进程服务时间用完时
{
printf(" %c finished.", q_ready->front->next->node.name); //finish表示此进程运行结束
for (int i = 0;i < n;i++) {
if (q_ready->front->next->node.name == ResultPCB[i].name) //遍历数组,找到与队首进程对应的项
{
ResultPCB[i].Finishtime = SumoperateTime; //把总时间作为完成时间赋值给对应的进程
}
}
DeleteQueueNode(q_ready); //注销队首进程
x = 0; //此时进程切换,时间片需要置0
}
else if (0<q_ready->front->next->node.Servicetime) //若队首进程还有服务时间
{
if (x < t) //如果不到时间片,则什么也不做,下次还是执行此队首进程
{
;
}
else //如果到达时间片,此时需要进行进程切换
{
x = 0; //无疑时间片需要置0
if (!q_ready->front->next->next) //如果队里只有一个进程,没必要放到队尾
{
;
}
else frontNodeTorear(q_ready); //如果有多个进程,则把队首进程移到队尾
}
}
if (!IsEmptyQueue(q_ready)) //队列不空
{
printf(" %c executing.\n",q_ready->front->next->node.name); //执行队首进程
--q_ready->front->next->node.Servicetime; //执行一次后服务时间减一
}
else //队列为空
{
printf("***没有进程运行\n");
}
++x; //累计时间片
++SumoperateTime; //累计总时间,用于明确各个进程完成时间
}
}
void InitQueue(LinkQueue* q) { //初始化头结点
q->front = q->rear = (QueueNode*)malloc(sizeof(QueueNode));
q->front->next = NULL;
}
bool IsEmptyQueue(LinkQueue* q) { //判空
if (q->front == q->rear)
return true;
return false;
}
void InsertQueueNode(LinkQueue* q, RR TempPCB) { //插入结点
QueueNode* P = (QueueNode*)malloc(sizeof(QueueNode));
P->node = TempPCB;
P->next = NULL;
q->rear->next = P;
q->rear = P;
}
bool DeleteQueueNode(LinkQueue* q) {
QueueNode* P = q->front->next;
if (IsEmptyQueue(q)) //为空无法删除
return false;
q->front->next = P->next; //使头结点指向第一个结点的下一个结点
if (P == q->rear) //如果P是尾指针,直接使队头等于队尾
q->rear = q->front;
free(P);
return true;
}
void frontNodeTorear(LinkQueue* q) { //用作把队首结点移到队尾
QueueNode* P = q->front->next;
q->front->next = P->next;
P->next = NULL; //首进程摘下来
q->rear->next = P; //尾部指针下一个指向摘下来的首进程
q->rear = P;
}
bool cmp(RR a, RR b) //排序辅助函数
{
return a.arrivaltime < b.arrivaltime;
}
运行实例如下:
时间片为4的情况:
时间片为1的情况: