设计目的
进程管理是操作系统中的重要功能,用来创建进程、撤消进程、实现进程状态转换,它提供了在可运行的进程之间复用CPU的方法。在进程管理中,进程调度是核心,因为在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态,当就绪进程个数大于处理器数目时,就必须依照某种策略决定哪些进程优先占用处理器。本设计模拟在单处理器情况下的进程调度,加深对进程运行状态和进程调度过程、调度算法的理解。
设计内容
设计程序模拟单处理机系统中的进程调度算法,实现动态优先权进程调度算法, 对N个进程采用动态优先权算法的进程调度。
设计思路
1.每个用来标识进程的进程控制块PCB,包括以下信息:进程标识数ID,进程优先数PRIORITY,进程已占用的CPU时间CPUTIME,进程还需占用的CPU时间NEEDTIME,进程状态STATE等。
2.优先数改变的原则:进程在就绪队列中呆一个时间片,优先数增加1,进程每运行一个时间片优先数减3。(注:优先数改变策略也可以自己设计)
3.设置调度前的初始状态。
4.将每个时间片内的进程情况显示出来。
实现提示:
1.就绪队列应包含如下操作:
入队操作:将新的进程按照优先级大小插入就绪队列,保证队列按优先级大小呈递减状态。
出队操作:将就绪队列中优先级最大的进程弹出队列,由于就绪队列中是按优先级大小排列的,所以也是弹出第一个就绪进程。
队列更新操作:每个时间片后,更新就绪队列中进程的优先级。每过一个时间片段后,就绪队列中每个进程的优先级+1。
2. 每个时间片后,按照一定格式输出各进程的状态。
算法流程图
程序结构
(1)初始化PCBInitPCB()
初始化进程控制块,已占用的CPU时间初始为0,进程状态初始为Ready,PCB的next为NULL。
(2)初始化链表InitLinkList()
链表首部分配一个PCB结构大小的头结点,next为NULL。
(3)头插法创建单链表CreatFromHead()
依次输入各进程的ID,PRIORITY,NEEDTIME构成就绪链表
(4)优先级排序PRIORITY_ARRAY()
冒泡排序法:优先级数从高到低排序
(5)空链表判断Ready_is_null()
(6)投入运行ToRunned()
①先判断链表是否为空,为空则结束,否则②
②从就绪链表中把首个进程状态为Ready的进程投入运行,并把状态改为Runned
③已占用CPU时间+1,仍需占用时间-1,如果已占用CPU时间已达到所需运行的时间,则释放该结点,否则④
④调用优先数改变算法把运行状态的优先级-3,就绪状态的优先级+1,然后把进程运行状态改回就绪状态
⑤完成一个时间片后输出进程情况
⑥调用优先级排序算法对就绪链表里的所有进程按优先级从高到低重新排序
⑦当就绪链表不为空则跳转②,否则结束程序
(7)优先数改变PRIORITY_CHANGE()
运行状态的优先级-3,就绪状态的优先级+1
(8)进程控制块情况show_PCB()
实现代码
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct PCB{
int ID; //进程标识数
int PRIORITY; //进程优先数
int CPUTIME; //进程已占用的CPU时间
int NEEDTIME; //进程还需占用的CPU时间
enum state STATE;//进程状态
struct PCB *next;
}Node,*LinkList;
enum state{Ready,Runned,Blocked};//定义一个枚举类型
char *state[]={"Ready","Runned","Blocked"};//方便输出进程状态的名称
void InitPCB(PCB *pcb);
void InitList(LinkList *L);
void CreatFromHead(LinkList L,int n);
void PRIORITY_ARRAY(LinkList L,int *n);
int Ready_is_null(LinkList L);
int ToRunned(LinkList L,int *n);
void PRIORITY_CHANGE(LinkList L);
void show_PCB(LinkList L);
void InitPCB(PCB *pcb) //初始化PCB
{
pcb->CPUTIME=0;
pcb->STATE=Ready;
pcb->next=NULL;
}
void InitList(LinkList *L) //初始化单链表
{
*L=(LinkList)malloc(sizeof(PCB)); //建立头结点
(*L)->next=NULL; //建立空的单链表L
}
void CreatFromHead(LinkList L,int n) //头插法创建单链表(就绪链表)
{
PCB *pcb; //定义一个指向PCB结点的指针
printf("请输入各个进程的标识数,优先数,需占用的CPU时间:\n");
for(int i=0;i<n;i++)
{
pcb=(Node *)malloc(sizeof(PCB));
InitPCB(pcb); //初始化PCB
scanf("%d %d %d",&pcb->ID,&pcb->PRIORITY,&pcb->NEEDTIME);//输入进程信息
pcb->next=L->next;
L->next=pcb;
}
printf("-------------------------------------------------------------------------------\n");
}
void PRIORITY_ARRAY(LinkList L,int *n) //冒泡排序:优先级数从高到低排序
{
PCB *r,*s,*t;
int change=TRUE;
for(int i=1;i<=(*n)-1&&change;i++) //排序n-1趟
{
r=L;
s=r->next;
t=s->next;
change=FALSE;
for(int j=1;j<=(*n)-1;j++) //冒泡n-i遍
if(s->PRIORITY<t->PRIORITY)
{
r->next=t; //排序
if(t->next!=NULL){s->next=t->next;t->next=s;}
else {t->next=s,s->next=NULL;}
r=r->next; //保持r,s,t的顺序继续扫描
t=s->next;
change=TRUE;
}
else if(s->PRIORITY>t->PRIORITY)
{
r=r->next;
s=s->next;
t=t->next;
}
}
}
int Ready_is_null(LinkList L)
{
if(L->next==NULL)
{
printf("就绪队列为空!\n");
return TRUE; //空则返回1
}
else return FALSE; //不空则返回0
}
int ToRunned(LinkList L,int *n)
{
if(Ready_is_null(L)) return 0;
PCB *s;
s=L->next;
s->STATE=Runned; //投入运行
s->CPUTIME+=1;
s->NEEDTIME-=1;
if(s->NEEDTIME==0)
{
printf("运行进程已占用CPU时间已达到所需运行的时间。已撤销进程:%d!\n",s->ID);
L->next=s->next;
free(s);(*n)-=1;
PRIORITY_CHANGE(L);
}
else
{
PRIORITY_CHANGE(L);
s->STATE=Ready;
}
show_PCB(L); //每运行完一个时间片后,输出各进程状态
PRIORITY_ARRAY(L,n);
if(Ready_is_null(L)) return 0;
else return 1;
}
void PRIORITY_CHANGE(LinkList L) //优先级数改变
{
PCB *t;
t=L->next;
while(t!=NULL)
{
if(t->STATE==1){t->PRIORITY-=3;t=t->next;}//进程在运行队列中呆一个时间片,优先数减3
if(t!=NULL&&t->STATE==0){t->PRIORITY+=1;t=t->next;}//进程在就绪队列中呆一个时间片,优先数增加1
}
}
void show_PCB(LinkList L) //当前所有进程状态
{
PCB *r;
r=L->next;
while(r!=NULL)
{
printf("进程标识符:%d,优先数:%d,已占CPU时间:%d,还需占用CPU时间:%d,当前状态为:%s\n",r->ID,r->PRIORITY,r->CPUTIME,r->NEEDTIME,state[r->STATE]);
r=r->next;
}
printf("-------------------------------------------------------------------------------\n");
}
int main()
{
LinkList L;
InitList(&L);
int n;
printf("请输入进程数:\n");
scanf("%d",&n);
CreatFromHead(L,n);
PRIORITY_ARRAY(L,&n);
while(ToRunned(L,&n));
return 0;
}
调试结果
参考文献
[1]耿国华.数据结构—用C语言描述(第2版)[M].北京:高等教育出版社,2015.7
[2]姜学锋.C程序设计[M].北京:清华大学出版社,2012.3
[3]胡元义.操作系统原理[M].北京:电子工业出版社,2018.8