经典时间片轮转RR算法C语言实现

本文深入探讨了RR(时间片轮转)算法的工作原理及其实现细节,通过具体代码示例,展示了进程调度中时间片轮转的具体操作,包括进程服务时间的管理和调度循环的控制。同时,文章还提供了运行实例,帮助读者理解不同时间片设置下的调度效果。

**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的情况:
在这里插入图片描述

### 时间片轮转调度算法概述 时间片轮转调度是一种常见的CPU调度策略,在Linux操作系统下广泛应用。该算法通过给定固定大小的时间片段(称为时间片),依次分配给各个等待中的进程,当一个进程运行了一个时间片后如果没有结束,则被中断并重新加入就绪队列尾部。 具体来说,`roundRobin`函数实现了这一逻辑[^1]: ```c #define TIME_SLICE 10 // 定义时间片长度为10单位时间 typedef struct Process { int id; int arrivalTime; int burstTime; // 所需总服务时间 int remaining; // 剩余需要的服务时间 } Process; // roundRobin 函数用于模拟RR调度过程 void roundRobin(Process processes[], int n) { int currentTime = 0, completed = 0; while (completed != n) { // 当还有未完成的任务时继续循环 for(int i=0;i<n && completed!=n;++i){ if(processes[i].remaining>0){ // 如果当前任务还未完成 printf("Process %d is running at time %d\n",processes[i].id ,currentTime); if(processes[i].remaining > TIME_SLICE){ currentTime += TIME_SLICE; processes[i].remaining -= TIME_SLICE; }else{ // 若剩余所需时间不超过时间片则一次性处理完毕 currentTime+=processes[i].remaining; processes[i].remaining=0; ++completed; printf("Process %d finished at time %d\n",processes[i].id ,currentTime ); } } } } } ``` 上述代码展示了如何利用C语言实现基本的时间片轮转调度机制。这里定义了结构体`Process`用来存储每个进程的信息;而核心部分则是`roundRobin()`方法,其内部采用双重迭代的方式遍历所有待处理的请求直到全部完成为止。每当遇到一个新的周期起点时,都会检查是否有新的作业可以开始执行,并按照既定规则调整它们的状态直至整个序列收敛于终止状态。 此外,还有一种变种形式——基于优先级的时间片轮转调度算法,这不仅考虑到了公平性原则同时也引入了权重概念使得某些重要程度更高的任务能够获得更多的计算资源支持。不过这部分涉及到更复杂的链表操作以及自定义比较器的设计[^2]。
评论 13
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值