文章目录
题目
代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct PCB* PCBPtr;
typedef struct PCB{
int ID;//进程标识数
int priority;//优先级
int CPUTime;//进程已占用CPU时间
int AllTime;//进程还需占用的CPU时间,运行完毕时为0
int StartBlock;//进程的阻塞时间,表示再运行StartBlock个时间片后,进入阻塞状态
int BlockTime;//进程被阻塞的时间,表示已阻塞的进程再等待BlockTime个时间片后将转换成就绪状态
int State;//进程状态
PCBPtr next;
}PCB;
typedef struct LinkQueue{
PCBPtr front, rear;//只保存队头队尾指针
}LinkQueue;
//初始化链队
void InitQueue(LinkQueue &Q){
Q.front = Q.rear = new PCB;//带有头结点,队头指针指向头结点,队尾指针指向队尾元素
Q.front->State = 99;
return;
}
//初始化PCB
PCBPtr InitPCB(PCB p){
PCBPtr t = new PCB;
*t = p;
t->next = NULL;
return t;
}
//入队
void EnQueue(LinkQueue &Q, PCB e){
Q.rear->next = InitPCB(e);
Q.rear = Q.rear->next;
return;
}
//出队
bool DeQueue(LinkQueue &Q, PCB &e){
if (Q.front == Q.rear)return false;
PCBPtr p = Q.front->next;//p为队头元素的指针
e = *p;
Q.front->next = p->next;//头结点和队头元素的后导重新挂接
if (Q.rear == p)//如果队头元素(头结点的后导)就是队尾元素(队尾指针指向)
Q.rear = Q.front;//最后一个元素删除,队尾指针指向头结点
delete p;
return true;
}
//判空
bool JudgeEmpty(LinkQueue Q){
if (Q.front == Q.rear)return true;
return false;
}
//取队头元素
PCB GetHead(LinkQueue Q){
return *Q.front->next;
}
int time,n,timeseg;//当前时间,进程数,时间片
//快排
void swap(PCB &a, PCB &b){
PCBPtr A = a.next, B = b.next;
PCB t = a;
a = b;
b = t;
a.next = A;
b.next = B;
return;
}
PCBPtr GetPivot(PCBPtr start, PCBPtr end){
PCBPtr p = start, q = start->next;
PCB key = *p;
while (1){
while (q->priority<=key.priority&&q != end)
q = q->next;
if (q->priority > key.priority&& p != end){
p = p->next;
swap(*p, *q);
}
if (q == end || p == end)
break;
}
swap(*start, *p);
return p;
}
void PrioritySort(PCBPtr start,PCBPtr end){
if (start != end){//不止一个元素
PCBPtr Pivot = GetPivot(start, end);
if (Pivot)
PrioritySort(start, Pivot);
if (Pivot->next)
PrioritySort(Pivot->next, end);
}
return;
}
void delay(int n){
while (n--){
for (int i = 0; i < 5; i++)
for (int j = 0; j < 500; j++);
}
return;
}
//输出
void ShowTime(LinkQueue Q){
if (JudgeEmpty(Q)){ printf("运行完毕\n"); return; }
printf("当前时刻为:%d\n", time);
printf("***********************各进程状态为************************\n");
printf("ID Priority CPUTime AllTime StartBlock BlockTime State\n");
Q.front = Q.front->next;
for (int i = 0;Q.front!=NULL; i++){
printf("%d %d %d %d %d %d %d\n", Q.front->ID, Q.front->priority, Q.front->CPUTime, Q.front->AllTime, Q.front->StartBlock, Q.front->BlockTime, Q.front->State);
Q.front = Q.front->next;
}
return;
}
//赋予状态:0-运行,1-阻塞,2-就绪,3-结束
void SaveState(LinkQueue &Q){
PCBPtr p = Q.front->next,f=NULL;
bool flag = false;
do{
if (p->BlockTime > 0&&p->State==1){
p->BlockTime--;
if (p->BlockTime == 0)//阻塞变为就绪
p->State = 2;
}
if (p->StartBlock > 0&&(p->State==2||p->State==0)){
p->StartBlock--;
if (p->StartBlock == 0)//就绪变为阻塞
p->State = 1;
}
if (!flag && (p->State == 2 || p->State == 0)){//就绪队列中优先级最高的进入运行
p->State = 0; flag = true;
}
else if (flag&&p->State == 0)//有运行的进程后再遇到运行状态就变回就绪状态
p->State = 2;
f = p;
p = p->next;
} while (f != Q.rear);
return;
}
//运行状态的PCB P经历了一个时间片
void AddProject(PCBPtr &P){
if (P->AllTime > timeseg){//未运行完
P->priority -= 3;
P->AllTime -= timeseg;//还需占用时间减少一个时间片
P->CPUTime += timeseg;//已占用增加一个时间片
}
else{//运行完
P->priority = 99;
P->CPUTime += P->AllTime;
P->AllTime = 0; P->StartBlock = 0; P->BlockTime = 0;
P->State = 3;
}
}
//一个时间片的时间的各个PCB的分配,状态:0-运行,1-阻塞,2-就绪,3-结束
void OpProject(LinkQueue &Q){
if (!JudgeEmpty(Q)){
PCBPtr p = Q.front->next,f=NULL;
SaveState(Q);//赋予状态
do{
if (p->State == 0)//运行的操作
AddProject(p);
if (p->State == 2){//就绪优先级+1
p->priority++;
}
f = p;
p = p->next;
} while (f != Q.rear);
PrioritySort(Q.front->next, Q.rear);
PCB t = GetHead(Q);
if (t.State == 3)
DeQueue(Q, t);
ShowTime(Q);//展示
}
return;
}
//菜单
void menu(LinkQueue &Q){
printf("请输入进程数:");
scanf("%d", &n);
printf("请设置时间片长度:");
scanf("%d", ×eg);
if (n > 0){
PCB e;
printf("请输入各进程初始状态:状态:0-运行,1-阻塞,2-就绪,3-结束\nID Priority AllTime StartBlock BlockTime State\n");
e.CPUTime = 0;
//写入
scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime,&e.State);
EnQueue(Q, e);
for (int i = 1; i < n; i++){
scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime, &e.State);
e.CPUTime = 0;
EnQueue(Q, e);
}
}
//输出0时刻的进程表
if (!JudgeEmpty(Q))//若非空,则优先级排序
PrioritySort(Q.front->next, Q.rear);
ShowTime(Q);
//getchar();getchar();
while (!JudgeEmpty(Q)){
delay(500000);
time+=timeseg;
OpProject(Q);
//getchar();
}
return;
}
int main(){
LinkQueue Q;
InitQueue(Q);
menu(Q);
system("pause");
return 0;
}
1.结构体及其操作
1.0结构体
typedef struct PCB* PCBPtr;
typedef struct PCB{
int ID;//进程标识数
int priority;//优先级
int CPUTime;//进程已占用CPU时间
int AllTime;//进程还需占用的CPU时间,运行完毕时为0
int StartBlock;//进程的阻塞时间,表示再运行StartBlock个时间片后,进入阻塞状态
int BlockTime;//进程被阻塞的时间,表示已阻塞的进程再等待BlockTime个时间片后将转换成就绪状态
int State;//进程状态
PCBPtr next;
}PCB;
typedef struct LinkQueue{
PCBPtr front, rear;//只保存队头队尾指针
}LinkQueue;
1.1初始化
//初始化链队
void InitQueue(LinkQueue &Q){
Q.front = Q.rear = new PCB;//带有头结点,队头指针指向头结点,队尾指针指向队尾元素
Q.front->State = 99;
return;
}
1.2入队
//初始化PCB
PCBPtr InitPCB(PCB p){
PCBPtr t = new PCB;
*t = p;
t->next = NULL;
return t;
}
//入队
void EnQueue(LinkQueue &Q, PCB e){
Q.rear->next = InitPCB(e);
Q.rear = Q.rear->next;
return;
}
1.3出队
//出队
bool DeQueue(LinkQueue &Q, PCB &e){
if (Q.front == Q.rear)return false;
PCBPtr p = Q.front->next;//p为队头元素的指针
e = *p;
Q.front->next = p->next;//头结点和队头元素的后导重新挂接
if (Q.rear == p)//如果队头元素(头结点的后导)就是队尾元素(队尾指针指向)
Q.rear = Q.front;//最后一个元素删除,队尾指针指向头结点
delete p;
return true;
}
1.4判空
//判空
bool JudgeEmpty(LinkQueue Q){
if (Q.front == Q.rear)return true;
return false;
}
1.5取队头元素
//取队头元素
PCB GetHead(LinkQueue Q){
return *Q.front->next;
}
1.6快排(根据优先权)
交换值而非地址,降序
p,q之间的数是小于等于key的
p之前的数是大于key的
最后交换start和p的值,使得p作为枢纽,前面的都是大于p的,后面的都是小于等于的的
//快排
void swap(PCB &a, PCB &b){
PCBPtr A = a.next, B = b.next;
PCB t = a;
a = b;
b = t;
a.next = A;
b.next = B;
return;
}
PCBPtr GetPivot(PCBPtr start, PCBPtr end){
PCBPtr p = start, q = start->next;
PCB key = *p;
while (1){
while (q->priority<=key.priority&&q != end)
q = q->next;
if (q->priority > key.priority&& p != end){
p = p->next;
swap(*p, *q);
}
if (q == end || p == end)
break;
}
swap(*start, *p);
return p;
}
void PrioritySort(PCBPtr start,PCBPtr end){
if (start != end){//不止一个元素
PCBPtr Pivot = GetPivot(start, end);
if (Pivot)
PrioritySort(start, Pivot);
if (Pivot->next)
PrioritySort(Pivot->next, end);
}
return;
}
2.动态优先权算法
2.1菜单
- 输入,依次进队
- 先快排一次,并输出(时刻0)
- 进入无限循环直到队空结束
3.1.延时
3.2.加一个时间片的时间
3.3进入加一个时间片的各个PCB的分配子函数(里头兼有快排及输出)
//菜单
//菜单
void menu(LinkQueue &Q){
printf("请输入进程数:");
scanf("%d", &n);
printf("请设置时间片长度:");
scanf("%d", ×eg);
if (n > 0){
PCB e;
printf("请输入各进程初始状态:状态:0-运行,1-阻塞,2-就绪,3-结束\nID Priority AllTime StartBlock BlockTime State\n");
e.CPUTime = 0;
//写入
scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime,&e.State);
EnQueue(Q, e);
for (int i = 1; i < n; i++){
scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime, &e.State);
e.CPUTime = 0;
EnQueue(Q, e);
}
}
//输出0时刻的进程表
if (!JudgeEmpty(Q))//若非空,则优先级排序
PrioritySort(Q.front->next, Q.rear);
ShowTime(Q);
//getchar();getchar();
while (!JudgeEmpty(Q)){
delay(500000);
time+=timeseg;
OpProject(Q);
//getchar();
}
return;
}
2.2加一个时间片的各个PCB的分配子函数
状态:0-运行,1-阻塞,2-就绪,3-结束
-
赋予各个PCB新的状态,改变BlockTime和StartBlock
注意:阻塞时间StartBlock只有由1-0=0这一次使得进程进入阻塞状态;同样的,被阻塞时间BlockTime只有由1-0=0这一次使得进程从阻塞状态进入就绪状态
-
改变优先级
优先级改变的原则:
2.1进程在就绪队列中呆一个时间片,优先数+1
2.2进程每运行一个时间片,优先数-3
- 优先级排序
- 如果队头是运行结束的进程,使其出队
(1)运行结束的进程被设置了奇高的优先级一定在队头;
(2)每次只运行一个进程,所以一次只会出现一个运行结束的进程 - 输出
//一个时间片的时间的各个PCB的分配,状态:0-运行,1-阻塞,2-就绪,3-结束
void OpProject(LinkQueue &Q){
if (!JudgeEmpty(Q)){
PCBPtr p = Q.front->next,f=NULL;
SaveState(Q);//赋予状态
do{
if (p->State == 0)//运行的操作
AddProject(p);
if (p->State == 2){//就绪优先级+1
p->priority++;
}
f = p;
p = p->next;
} while (f != Q.rear);
PrioritySort(Q.front->next, Q.rear);
PCB t = GetHead(Q);
if (t.State == 3)
DeQueue(Q, t);
ShowTime(Q);//展示
}
return;
}
2.2.1赋予各个PCB新的状态
状态:0-运行,1-阻塞,2-就绪,3-结束
因为在这之前输出的进程表总是已按优先级排序过的的
所以这里优先级最高的且不阻塞的就是接下来进入运行状态的进程
遍历整个队列:
- 运行进程只有一个,找到第一个优先级最高的且不阻塞的赋为运行状态-0
- 每个每个大于0的StartBlock和BlockTime都随着时间片的消耗而-1;若是由1变为0则触发功能(StartBlock使进程进入阻塞状态-1;BlockTime使阻塞进程进入就绪状态)
- 若已分配过运行进程后,又遇到状态为0-运行的进程,则赋其为就绪状态-2
//赋予状态:0-运行,1-阻塞,2-就绪,3-结束
void SaveState(LinkQueue &Q){
PCBPtr p = Q.front->next,f=NULL;
bool flag = false;
do{
if (p->BlockTime > 0&&p->State==1){
p->BlockTime--;
if (p->BlockTime == 0)//阻塞变为就绪
p->State = 2;
}
if (p->StartBlock > 0&&(p->State==2||p->State==0)){
p->StartBlock--;
if (p->StartBlock == 0)//就绪变为阻塞
p->State = 1;
}
if (!flag && (p->State == 2 || p->State == 0)){//就绪队列中优先级最高的进入运行
p->State = 0; flag = true;
}
else if (flag&&p->State == 0)//有运行的进程后再遇到运行状态就变回就绪状态
p->State = 2;
f = p;
p = p->next;
} while (f != Q.rear);
return;
}
2.2.2运行状态的PCB P经历了一个时间片的分配状况
- 若未运行完
优先级-3
还需占用时间减少一个时间片
已占用增加一个时间片
- 若运行完
优先级赋奇高,这里赋为99,使得快排后其必然在队头
状态赋为结束-3
//运行状态的PCB P经历了一个时间片
void AddProject(PCBPtr &P){
if (P->AllTime > timeseg){//未运行完
P->priority -= 3;
P->AllTime -= timeseg;//还需占用时间减少一个时间片
P->CPUTime += timeseg;//已占用增加一个时间片
}
else{//运行完
P->priority = 99;
P->CPUTime += P->AllTime;
P->AllTime = 0; P->StartBlock = 0; P->BlockTime = 0;
P->State = 3;
}
}