课程名:操作系统原理及Linux应用
内容/作用:设计/实验/作业/练习
学习:基于Linux的处理机调度时间片轮转法
一、前言
- 了解Linux下Emacs编辑器的使用方法,掌握各种常用的键盘操作命令;
- 理解并掌握处理机调度算法。
二、环境与设备
1.软件:虚拟机VMware
2.环境:Linux系统环境
三、原理
在采用多道系统的设计程序中,往往有若干进程同时处于就绪状态。当就绪状态进程数大于处理机数时,就必须按照某种策略来决定哪些进程优先占用处理机。本实验模拟在单处理机情况下处理机调度。
1、优先调度算法实现处理机的调度:
设计思路:
1)每个进程用一个进程控制块PCB来代表,进程控制块包括进程名(进程的标识)、指针(按优先数的大小把进程连成队列,用指针指出下一个进程的进程控制块首地址,最后一个进程中的指针为"0")、要求运行时间、优先数、状态(就绪、结束);
2)每次运行处理机调度程序前,为每个进程确定它的"优先数"和"要求运行时间";
3)把给定的进程按优先数的大小连成队列,用一单元指出队首进程;
4)每模拟执行一次进程,优先数减一,要求运行时间减一;
5)如果要求运行的时间>=0,再将它加入队列(按优先数的大小插入,重置队首标志);如果要求运行的时间=0,那么把它的状态修改为结束,且退出队列;
6)若就绪队列不为空,重复上述,直到所有的进程都结束;
7)程序有显示和打印语句,每次运行后显示变化。
2、按时间片轮转法实现处理机调度:
设计思路:
1)每个进程用一个进程控制块PCB来代表,进程控制块包括进程名(进程的标识)、指针(把进程连成循环队列,用指针指出下一个进程的进程控制块首地址,最后一个进程中的指针指出第一个进程的进程控制块首地址)、已运行时间、状态(就绪、结束);
2)每次运行处理机调度程序前,为每个进程确定它的"要求运行时间";
3)用指针把给定的进程按顺序排成循环队列,用另一标志单元记录轮到的进程;
4)每模拟运行一次进程,已运行时间加一;
5)进程运行一次后,把该进程控制块的指针值送到标志单元,以指示下一个轮到的进程。若该进程要求运行时间≠已运行时间,未执行结束,待到下一轮再执行;若要求运行时间=已运行时间,状态改为结束,退出队列;
6)若就绪队列不为空,重复步骤四和五;
7)程序有显示和打印语句,每次运行后显示变化。
四、内容
1、时间片轮转法:
#include<stdio.h>
#include<queue>
#include<math.h>
#include<vector>
#include<iostream>
#include <iomanip>
using namespace std;
/*进程的数据结构*/
struct PCB
{
int ID;//进程ID
double in_time;//进程的进入时间
double res_time;//进程的响应时间
double l_time;//进程的剩余时间
};
/*进程调度函数 */
/*输入:进程队列prs,时间片timeslice */
/*输出:进程状态表 */
void ProcessScheduling(queue<PCB>prs,double timeslice)
{
cout << left;
queue<PCB>ex_prs;//就绪队列,该队列中的进程是等待执行的
ex_prs.push(prs.front());//第一个进程首先进入就绪队列
prs.pop();//将第一个进程退出进程队列
double slice_start;//时间片开始时间
double slice_end = 0;//时间片结束时间
cout << "----------------------------------进程状态表------------------------------------" << endl;
cout <<setw(15)<<"进程ID" << "|" << setw(15) << "到达时间" << "|" <<setw(15) << "总响应时间" << "|" << setw(15) << "时间片开始时间"<<"|" << setw(15) <<"时间片结束时间"<<"|"<< endl;
cout << "--------------------------------------------------------------------------------" << endl;
while (!prs.empty()||!ex_prs.empty())
{
slice_start = slice_end;//更新时间片开始与结束时间
slice_end += timeslice;//每次增加一个时间片的时间
while (!prs.empty())
//每次执行一个进程前,将能在此进程占用cpu期间进入就绪队列的进程加入就绪队列
{
if (prs.front().in_time > slice_end)break;
ex_prs.push(prs.front());
prs.pop();
if (ex_prs.size() == 1)
{
slice_start = slice_end;
slice_end += timeslice;
}
}
//如果就绪队列为空则继续while循环
if (ex_prs.empty())continue;
//如果剩余时间小于或等于时间片
if (ex_prs.front().l_time <= timeslice)
{
ex_prs.front().l_time = 0;//将进程的剩余时间置为0(可有可无)
cout << setw(15) << ex_prs.front().ID << "|" << setw(15) << ex_prs.front().in_time << "|" << setw(15) << ex_prs.front().res_time << "|" << setw(15) << slice_start<<"|"<< setw(15) << slice_end<<"|"<< endl;
ex_prs.pop();
}
else
{
ex_prs.front().l_time -= timeslice;//将进程的剩余时间减少一个时间片
cout << setw(15) << ex_prs.front().ID << "|" << setw(15) << ex_prs.front().in_time << "|" << setw(15) << ex_prs.front().res_time << "|" << setw(15) << slice_start << "|" << setw(15) << slice_end <<"|"<< endl;
//将队首进程置于队尾
PCB tmp_pr = ex_prs.front();
ex_prs.pop();
ex_prs.push(tmp_pr);
}
}
cout << "--------------------------------------------------------------------------------" << endl;
}
int main()
{
queue<PCB>prs;
//总响应时间
double allres_time = 0;
//时间片
double timeslice = 0;
PCB pr1, pr2, pr3;
pr1 = { 1,0,10,10 };
pr2 = { 2,1,5,5 };
pr3 = { 3,2,5,5 };
allres_time += pr1.res_time + pr2.res_time + pr3.res_time;
timeslice = allres_time / 3;
prs.push(pr1);
prs.push(pr2);
prs.push(pr3);
cout << "时间片为:" << timeslice << endl;
ProcessScheduling(prs, timeslice);
cout << "添加进程?(y/n):";
char i;
cin >> i;
while (i-'y'==0)
{
PCB pr;
cout << "请输入进程ID:";
cin >> pr.ID;
cout << "请输入进程到达时间:";
cin >> pr.in_time;
cout << "请输入进程响应时间:";
cin >> pr.res_time;
cout << "请输入进程剩余时间:";
cin >> pr.l_time;
prs.push(pr);
allres_time += pr.res_time;
timeslice = allres_time / prs.size();
cout << "时间片为:" << timeslice << endl;
ProcessScheduling(prs, timeslice);
cout << "继续添加进程?(y/n):";
cin >> i;
}
return 0;
}
五、总结与分析
思路:先主函数输入要进行调度的进程数,然后调用函数create(),把进程的信息输入,再调用函数insert(),把输入的函数按照优先数的大小排成链表,然后调用函数prio()实现优先数调度。