目录
一、实验目的
- 在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。
- 当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用处理器。
- 本实验模拟在单处理器情况下的处理器调度,帮助学生加深了解处理器调度的工作。
二、实验内容
- 设计一个程序,根据不同的调度算法模拟操作系统对进程的调度。
- 动态优先级法
- 设计进程控制块PBC表结构,分别适用优先数调度算法
- PBC结构通常包括以下信息:进程名、进程优先数、轮转时间片、进程的CPU时间,进程状态等。根据调度算法不同,PCB结构可作适当的调整。
- 建立进程队列。对不同的算法编制不同的入链程序。
- 程序要求达到的运行效果:在设置好进程数量、调度算法后,系统能按设定的参数运行,并在屏幕上交替显示就绪队列和完成队列的进程名等信息。
三、实验原理
设计一个按优先数调度算法实现处理器调度的程序。
- 假定系统有五个进程每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:
进程名 |
指针 |
要求运行时间 |
优先数 |
状态 |
其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。
指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。
要求运行时间——假设进程需要运行的单位时间数。
优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。
- 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。
- 为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例:
队首标志
K2
K1 | P1 | K2 | P2 | K3 | P3 | K4 | P4 | K5 | P5 |
| 0 |
| K4 |
| K5 |
| K3 |
| K1 |
| 2 |
| 3 |
| 1 |
| 2 |
| 4 |
| 1 |
| 5 |
| 3 |
| 4 |
| 2 |
| R |
| R |
| R |
| R |
| R |
| PCB1 |
| PCB2 |
| PCB3 |
| PCB4 |
| PCB5 |
- 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行:
优先数-1
要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。
- 进程运行一次后,若要求运行时间¹0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。
- 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。
- 在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。
- 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
四.算法流程图
五.源程序及注释
struct pcb /* 定义进程控制块PCB */ {
char name[10];//存储进程名
struct pcb* next; //指针
int super; //优先级数
int ntime; //运行时间
int rtime;
char state; //进程状态
}*ready = NULL, *p;
typedef struct pcb PCB;
- 程序包含函数:
input(); /* 建立进程控制块函数*/
sort(); /* 建立对进程进行优先级排列函数*/
disp(PCB * pr) ;/*建立进程显示函数,用于显示当前进程*/
check() ;// 建立进程查看函数
destroy(); /*建立进程撤消函数(进程运行结束,撤消进程)*/
running(); /* 建立进程就绪函数(进程运行时间到,置就绪状态*/
main(void) {
}/*主函数*/
- 打印一份源程序并附上注释。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define getpch(type) (type*)malloc(sizeof(type))
struct pcb /* 定义进程控制块PCB */ {
char name[10];//存储进程名
struct pcb* next; //指针
int super; //优先级数
int ntime; //运行时间
int rtime;
char state; //进程状态
}*ready = NULL, *p;
typedef struct pcb PCB;
void sort() /* 建立对进程进行优先级排列函数*/ {
PCB *first, *second;
int insert = 0;
if ((ready == NULL) || ((p->super) > (ready->super))) /*优先级最大者,插入队首*/
{
p->next = ready;//插入的数据作为链表头结点
ready = p;//头结点指针指向插入数
}
else /* 进程比较优先级,插入适当的位置中*/ {
first = ready;
second = first->next;
while (second != NULL)
{
if ((p->super) > (second->super)) /*若插入进程比当前进程优先数大,*/
{ /*插入到当前进程前面*/
p->next = second;
first->next = p;
second = NULL;
insert = 1;
}
else /* 插入进程优先数最低,则插入到队尾*/
{
first = first->next;
second = second->next;
}
}
if (insert == 0)
first->next = p;
}
}
void input() /* 建立进程控制块函数*/
{
int i, num;
printf("\n 请输入进程数:");
scanf("%d", &num);
for (i = 0; i < num; i++)
{
printf("\n 进程号%d:\n", i + 1);
p = getpch(PCB);
printf("\n 输入进程名:");
scanf("%s", p->name);
printf("\n 输入进程优先数:");
scanf("%d", &p->super);
printf("\n 输入进程运行时间:");
scanf("%d", &p->ntime);
printf("\n");
p->rtime = 0; p->state = 'w';
p->next = NULL;
sort(); //调用sort函数
}
}
int space()
{
int len = 0; PCB* pr = ready;
while (pr != NULL)
{
len++;
pr = pr->next;
}
return(len);
}
void disp(PCB * pr) /*建立进程显示函数,用于显示当前进程*/
{
printf("\n qname \t state \t super \t ndtime runtime \n");
printf("|%s\t", pr->name);
printf("|%c\t", pr->state);
printf("|%d\t", pr->super);
printf("|%d\t", pr->ntime);
printf("|%d\t", pr->rtime);
printf("\n");
}
void check() // 建立进程查看函数
{
PCB* pr;
printf("\n **** 当前正在运行的进程是:%s", p->name); //显示当前运行进程
disp(p);
pr = ready;
printf("\n ****当前就绪队列状态为:\n"); //显示就绪队列状态
while (pr != NULL)
{
disp(pr);
pr = pr->next;
}
}
void destroy() /*建立进程撤消函数(进程运行结束,撤消进程)*/
{
printf("\n 进程 [%s] 已完成.\n", p->name);
free(p);
}
void running() /* 建立进程就绪函数(进程运行时间到,置就绪状态*/
{
(p->rtime)++;
if (p->rtime == p->ntime)
destroy(); /* 调用destroy函数*/
else
{
(p->super)--;
p->state = 'w';
sort(); /*调用sort函数*/
}
}
int main(void) /*主函数*/
{
while (true)
{
int len;//
char ch;
input();
len =space();
while ((len != 0) && (ready != NULL))
{
ch = getchar();
p = ready;
ready = p->next;
p->next = NULL;
p->state = 'R';
check();
running();
system("pause");
}
printf("\n\n 进程已经完成.\n");
}
system("pause");
return 0;
}
六.运行结果
七.实验小结
1.基本思想:为每个进程设置一个优先级,在调度的时候,选取优先级最大的任务去执行。
2.优先级可以是静态赋予:创建任务的时候,就指定优先级大小,并且保持不变,直到任务结束。
3.也可以是动态赋予:优先级在执行任务中动态改变。
4.为了防止高优先级进程无休止地运行下去,调度程序可以在每个时钟中断降低当前进程的优先级。
5.在平时中,我们可以把不同的任务划分为不同的优先级,然后在相同优先级的任务中使用时间片轮转。