一、实验内容:
1、使用优先数调度算法完成进程的调度
- 采用动态优先数法确定进程的优先级别。
- 设计三个链队列,分别用来表示运行队列、就绪队列和完成队列。
- 用户输入进程标识符以及进程所需要的时间,申请空间存放进程PCB信息。
注:动态优先数法使进程的优先权随时间而改变。初始的进程优先数取决于进程运行所需要的时间,时间长则优先数低。可采取将进程优先数定为一个较大的数(比如50)减去进程运行所需要的时间。
2、使用时间片轮转算法完成进程的调度
时间片轮转调度:是调度程序每次把CPU分配给当前最高优先级进程使用一个时间片。当这个时间片结束时,强迫该进程让出处理器,进行下一轮优先级调度,直至就绪队列中所有进程都运行完成为止。
3、实现进程的创建、运行、删除以及显示其具体信息
哈哈哈哈,先给大家放源码吧。后面有我有具体怎么写的以及每个函数做什么,码字不易呀,如果喜欢留下你的小心心
二、源码(C++)
#include<stdio.h>
#include<iostream>
using namespace std;
//定义pcb
struct pcb {
char name[10];//进程标识符
int prio;//进程优先数
int round;//进程时间片轮转时间片
int needtime;//进程完成还需要时间
int rtime;//进程已经执行时间
int sumtime;//进程需要的总时间
char state;//进程的状态
pcb* next;//链指针
};
//创建运行队列,就绪队列,完成队列
pcb* Rqueue = new pcb();
pcb* Wqueue = new pcb();
pcb* Fqueue = new pcb();
pcb* p1 = Rqueue;
pcb* p2 = Wqueue;
pcb* p3 = Fqueue;
//计算获取优先级数
int getprio(int needtime) {
return 50 - needtime;
}
//链接进程
void linkpcb(pcb* progress) {
pcb* first, * second;
if (progress->state == 'R') {
p1->next = progress;
p1 = progress;
}
if (progress->state == 'W') {
if (Wqueue->next == NULL || (progress->prio) <= (p2->prio)) {
p2->next = progress;
p2 = progress;
}
else //比较进程优先级,插入适当的位置中
{
first = Wqueue;
second = first->next;
while (second != NULL)
{
if ((progress->prio) > (second->prio))
{
//若插入进程比当前进程优先数大,插入到当前进程前面
progress->next = second;
first->next = progress;
break;
}
else //若插入进程优先数最低,则插入到队尾
{
first = first->next;
second = first->next;
}
}
}
}
if (progress->state == 'F') {
p3->next = progress;
p3 = progress;
}
}
//进程的输入
void input()
{
pcb* p;
int num, round1;
system("cls");
printf(" ***************************动态最高优先级优先调度算法******************************");
printf("\n 请输入即将运行的进程总数目:");
scanf_s("%d", &num);
printf("\n 请输入时间片大小:");
scanf_s("%d", &round1);
for (int i = 1; i <= num; i++)
{
p = (pcb*)malloc(sizeof(pcb));
printf("\n 请输入第%d进程名称:", i);
cin >> p->name;
printf("\n 请输入第%d进程运行所需时间:", i);
cin >> p->needtime;
p->sumtime = p->needtime;
printf("\n");
p->round = round1;
p->rtime = 0;
p->state = 'W';
p->prio = getprio(p->needtime);
p->next = NULL;
linkpcb(p);
}
}
//进程显示的表头
void display1()
{
printf("\n进程名\t状态\t优先数\t总时间\t运行还需的时间\t已运行时间\n");
}
//显示进程信息
void display2(pcb* progress)
{
printf("|%s\t|%c\t|%d\t|%d\t|%d\t\t|%d", progress->name, progress->state, progress->prio, progress->sumtime, progress->needtime, progress->rtime);
printf("\n");
}
//进程查看函数
void check()
{
pcb* pr = Rqueue;
pcb* pw = Wqueue;
pcb* pf = Fqueue;
printf("\n------------------------------------------------------");
//运行队列
printf("\n(1)当前运行队列中进程的状态如下:");
if (pr->next == NULL)
printf("\n 当前无运行进程");
else
printf("\n 当前正在运行的进程是%s,优先数为%d,运行还需时间为%d", pr->next->name, pr->next->prio, pr->next->needtime);
//就绪队列
printf("\n(2)当前就绪队列中进程的状态如下:");
if (pw->next == NULL)
printf("\n 就绪队列为空!");
else
{
display1();
while (pw->next != NULL)
{
display2(pw->next);
pw = pw->next;
}
}
//完成队列
printf("\n(3)当前完成队列中进程的状态如下:");
if (pf->next == NULL)
printf("\n 完成队列为空!");
else
{
display1();
while (pf->next != NULL)
{
display2(pf->next);
pf = pf->next;
}
}
}
//进程运行
void run()
{
pcb* progress = Wqueue->next;
Wqueue->next = progress->next;//将progress从就绪队列中删去
if (Wqueue->next == NULL)
p2 = Wqueue;
progress->state = 'R'; //将progress的状态置为运行态
progress->next = NULL;
linkpcb(progress); //将progress插入运行队列
check();//显示进程状态
if (progress->needtime >= progress->round) { //判断剩余时间与时间片大小的关系
progress->rtime = progress->rtime + progress->round;
progress->needtime = progress->needtime - progress->round;
}
else {
progress->rtime = progress->rtime + progress->needtime;
progress->needtime = 0;
}
progress->prio = getprio(progress->needtime);//每一次运行结束需重新获取其优先级数
Rqueue->next = progress->next;//将progress从运行队列中删去
p1 = Rqueue;
if (progress->needtime == 0) {
progress->state = 'F';
linkpcb(progress);
printf("\n 进程 [%s] 已完成.\n", progress->name);
}
else
{
progress->state = 'W'; //将progress的状态置为就绪态
linkpcb(progress); //将progress插入就绪队列
}
}
int main() {
pcb* head = Wqueue;
input();
printf("\n 初始时的状态如下:");
check();
printf("\n\n 开始运行:..............");
while (head->next != NULL) {
run();
}
check();
printf("\n 进程已经全部完成.\n");
return 0;
}
三、思想原理
首先明确一个进程控制会应包含哪些信息,再进行pcb的封装。比如:进程标识符(name)、进程优先数(prio)、进程时间片(round)、进程已经执行时间(rtime)、进程还需要的时间(needtime)、进程需要总时间(sumtime)、进程的状态(state),以及链指针(next)。其次,每个进程在某个时刻一定会处于就绪或运行或完成状态。所以设计了三个链表,分别表示就绪队列(Wqueue)、运行队列(Rqueue)和完成队列(Fqueue)。最后明确所算进程调度的算法,此次实验我们选取的是动态优先级的时间片轮转调度。第一进程的优先级不是一成不变的,会随着它的运行而改变。第二当进程获取CPU的使用权时,不能运行任意时间大小,而是达到一个时间片限制到的时间,必须交出CPU的使用权。如果运行未结束,就进入就绪队列等待。
1、获取优先级的函数(getprio)
这里优先级的计算是一个较大的数50减去进程运行还需要的时间。直接在函数中返回50-needtime。
2、进程间的连接(linkpcb)
在程序中有三个队列对应进程三个不同的状态。首先在函数的开始时,我们要对进程的状态进行判断使其进入对应的队列。在这三个队列中。较为复杂的是就绪队列,因为在进程运行一个时间片之后可能由于没有运行完成,还会再次进入就绪队列。而且进程的优先级是不断变化的,所以在进入就绪队列之前还需要进行额外优先级大小的判断。
(1)进程状态为运行态‘R’
首先使指针p1指向运行队列的头结点,当进程progress来到时,将其插入在p1指向结点之后。并移动指针p1指向当前进程progress。
(2)进程状态为完成态‘F’
首先使指针p3指向完成队列的头结点,当进程progress来到时,将其插入在p3指向结点之后。并移动指针p3指向当前进程progress。
(3)进程状态为就绪态‘W’
当就绪队列为空或者进程progress的优先级小于或等于p2指向进程的优先级,就可直接将进程插入在P2所指向的进程之后。当进程的优先级大于p2指向进程的优先级就通过遍历就绪队列找到一个合适进程(其优先级小于进程progress)之前插入。
3、进程的输入(input)
首先输入即将运行的进程总数目以及时间片的大小,通过进程总
数目制循环次数,依次输入进程标识符,进程需要总时间。对进程标识符、进程已经执行时间、进程还需要的时间、进程需要总时间、进程的状态进行初始化。调用获取优先级函数初始化进程的优先数,调用进程连接函数对进程进行连接。
4、进程查看函数(check)
设置进程的查看函数对不同的三个队列进行输出查看。了解各进程处于什么样的状态。为了实现代码的复用性以及输出的友好性,我额外设置了两个显示函数(display1和display2)。第一个显示函数用于显示表头,第二个显示函数用于显示进程的具体信息。在查看函数中依次输出各队列的情况,并调用两个显示函数进行显示。
5、运行函数(run)
判断剩余时间与时间片大小的关系。
(1)进程还需要的时间大于时间片大小
更新进程已经执行时间为进程已经执行时间加上时间片的大小。
更新还需要运行时间等于还需要运行时间减去时间片的大小。
(2)进程还需要的时间小于时间片大小
更新进程已经执行时间为进程已经执行时间加上进程还需要的时间。
更新还需要运行时间等于零。
运行完成后重新调用获取优先级函数更新进程的优先数并判断程还需要的时间是否为零。若为零将进程progress插入完成队列并将其状态置为 ’F’。不为零则将进程progress插入就绪队列并将其状态置为 ’W’。
四、效果截图
1、输入样例
2、结果展示
。。。。。
图片太多就不一一显示了,可以自己运行看看