优先级调度算法(抢占式)
优先级调度算法有两种:一个是非抢占式优先级调度算法,另一个是抢占式优先级调度算法。
优先级调度算法(抢占式)规定,在把处理机分配给优先级最高的进程并使之执行时,只要出现了另一个优先级更高的进程,调度程序就会将处理机分配给新到的优先级更高的进程。因此,在采用这种调度算法时,每当系统中出现一个新的就绪进程 时,系统就会将其优先级
同正在执行的进程
的优先级
进行比较,如果
≤
,则原进程;继续执行;但如果
>
.则立即停止原进程
的执行并进行进程切换,使新进程
投入执行。抢占式优先级调度算法常用于对实时性要求较高的系统中。
举个栗子:
进程 | 到达时间 | 运行时间 | 优先数 |
P1 | 0 | 7 | 1 |
P2 | 2 | 4 | 2 |
P3 | 4 | 1 | 3 |
P4 | 5 | 4 | 2 |
- 0-2时刻:P1到达,只有P1在运行 P1(7-2)
- 2-4时刻:P2到达,P1优先级小于P2 ,P2开始运行 P2(4-2)
- 4-5时刻:P3到达, P3优先级大于P2,P3开始运行 P3(1-1) P3完成
- 5-7时刻:P4到达,P3已经运行结束,释放,P2与P4同级,P2先进入队列,P2运行,P2(4-2-2) P2完成
- 7-11时刻:P4运行,P4(4-4) P4完成
- 11-16时刻:P1运行 P1(7-2-5) P1完成
附上部分代码: 找到优先级最高且未完成的进程进行调度,同时更新其状态和优先级
void cpuexe(struct pcb *q)
{
struct pcb *t = q; // 初始化为链表的头指针,用于追踪当前最高优先级的进程。
int max_priority = 0;
while (q)
{ // 如果进程的状态不是 finish,将其状态设置为 ready
if (q->process != finish)
{
q->process = ready;
if (q->needtime == 0)
{
q->process = finish;
}
}
// 更新最高优先级
if (max_priority < q->priority && q->process != finish)
{
max_priority = q->priority;
t = q;
}
q = q->next;
}
if (t->needtime != 0)
{
t->priority -= 3; // 将该进程的优先级减少 3,以便在下一轮调度时降低其优先级
t->needtime--; // 该进程已使用 1 个 CPU 时间单位
t->process = execute;
t->cputime++; // 记录该进程使用的 CPU 时间
}
}
轮转调度算法
在分时系统中,最简单也是较常用的进程调度算法是基于时间片的轮转(roundrobin,RR)调度算法。该算法采取了非常公平的处理机分配方式,即让就绪队列上的每个进程每次仅运行个时间片。如果就绪队列上有n个进程,则每个进程每次大约可获得1/n的处理机时间。
在RR调度算法中,系统会将所有的就绪进程按FCFS策略排成一个就绪队列。系统可设置每隔一定时间(如30ms)便产生一次中断,去激活进程调度程序进行调度,把处理机分配给队首进程,并令其执行一个时间片。当它运行完后,再把处理机分配给就绪队列中新的队首进程,同样地让它也执行一个时间片。这样,就可以保证就绪队列中的所有进程,在确定的时间段内,都能获得一个时间片的处理机时间。
举个栗子:
进程 | 到达时间 | 运行时间 |
P1 | 0 | 7 |
P2 | 2 | 4 |
P3 | 4 | 1 |
P4 | 5 | 4 |
设cpu时间片为2。
- 0-2时刻: P1到达,P1(7-2)。队列(【P1】NULL)(【】为运行进程)
- 2-4时刻: P2到达,P2(4-2),在4时刻,P3到达,队列(【P2】 P1 -->P3)
- 4-5时刻:P1运行,P1(7-2-1),P4到达,队列(【P1】P3-->P2-->P4)
- 5-6时刻:P1依然在运行,P1(7-2-2), 队列(【P1】P3-->P2-->P4)
- 6-7时刻:P3运行,P3(1-1) P3运行完成 队列(【P3】P2-->P4-->P1)
- 7-9时刻:P2运行,P2(4-2-2) P2运行完成 队列(【P2】P4-->P1)
- 9-11时刻:P4运行,P4(4-2) 队列(【P4】P1)
- 11-13时刻:P1运行,P1(7-2-2-2) 队列(【P1】P4)
- 13-15时刻:P4运行,P4(4-2-2) P4运行完成 队列(【P4】P1)
- 15-16时刻 :P1运行,P1(7-2-2-2-1) 运行完成
优先级调度算法(抢占式)与轮转调度算法代码
#include <stdio.h>
#include <dos.h>
#include <stdlib.h>
#include <conio.h>
#include <io.h>
#define P_NUM 3
#define P_TIME 50
enum state
{ /*枚举类型*/
ready, // 就绪
execute, // 执行
block, // 阻塞
finish // 完成
};
struct pcb
{ /*进程控制块数据结构*/
char name[4];
int priority;
int cputime; // 进程已使用的CPU时间
int needtime; // 进程所需的CPU时间
int count; // 进程被调度的次数或时间片计数
int round; // 时间片轮转调度中的时间片使用次数
enum state process;
struct pcb *next;
};
struct pcb *get_process(); /*进程建立*/
struct pcb *get_process()
{
struct pcb *q; // 用于存储新创建的进程节点的指针
struct pcb *t; // 用于存储链表中的最后一个进程节点的指针
struct pcb *p; // 用于存储链表头节点的指针
int i = 0;
printf("input name and needtime, please input 3 processes\n");
while (i < P_NUM)
{
// 创建新的进程节点
q = (struct pcb *)malloc(sizeof(struct pcb));
scanf("%s", &(q->name));
scanf("%d", &(q->needtime));
q->cputime = 0;
q->priority = P_TIME - q->needtime; // 通过剩余时间初始化优先级
q->process = ready; // 初始状态为 "就绪" 状态
q->next = NULL; // 新建节点的 "next" 设为 NULL
// 将新创建的节点插入到进程链表中
if (i == 0)
{ // 第一个进程,初始化链表头指针 p 和 t
p = q;
t = q;
}
else
{
t->next = q;
t = q;
}
i++;
} /*while*/
// 结构类似于q1(p)-->q2-->q3(t)
return p;
}
// 遍历链表中的 PCB,输出每个进程的详细信息
void display(struct pcb *p)
{
printf("name cputime needtime priority state\n");
while (p)
{
printf("%s", p->name);
printf(" ");
printf("%d", p->cputime);
printf(" ");
printf("%d", p->needtime);
printf(" ");
printf("%d", p->priority);
printf(" ");
switch (p->process)
{
case ready:
printf("ready\n");
break;
case execute:
printf("execute\n");
break;
case block:
printf("block\n");
break;
case finish:
printf("finish\n");
break;
}
p = p->next;
}
}
int process_finish(struct pcb *q)
{ /*进程是否结束,当还有进程没有结束时返回0*/
int bl = 1;
while (bl && q)
{
bl = bl && q->needtime == 0;
q = q->next;
}
return bl;
}
void cpuexe(struct pcb *q)
{
struct pcb *t = q; // 初始化为链表的头指针,用于追踪当前最高优先级的进程。
int max_priority = 0;
while (q)
{ // 如果进程的状态不是 finish,将其状态设置为 ready
if (q->process != finish)
{
q->process = ready;
if (q->needtime == 0)
{
q->process = finish;
}
}
// 更新最高优先级
if (max_priority < q->priority && q->process != finish)
{
max_priority = q->priority;
t = q;
}
q = q->next;
}
if (t->needtime != 0)
{
t->priority -= 3; // 将该进程的优先级减少 3,以便在下一轮调度时降低其优先级
t->needtime--; // 该进程已使用 1 个 CPU 时间单位
t->process = execute;
t->cputime++; // 记录该进程使用的 CPU 时间
}
}
void priority_cal()
{ /*优先数调度*/
struct pcb *p;
int cpu = 0; // 记录 CPU 执行的时间
p = get_process(); // p是头指针
while (!process_finish(p))
{
cpu++;
printf("cputime:%d\n", cpu);
cpuexe(p); // 运行
display(p); // 输出每个进程的详细信息
sleep(5);
}
printf("All processes have finished,press any key to exit");
getch();
}
void display_menu()
{
printf("CHOOSE THE ALGORITHM:\n");
printf("1 PRIORITY\n");
printf("2 ROUNDROBIN\n");
printf("3 EXIT\n");
}
struct pcb *get_process_round()
{ /*轮转进程建立 头进尾插*/
struct pcb *q;
struct pcb *t;
struct pcb *p;
int i = 0;
printf("input name and time,please input 3 processes\n");
while (i < P_NUM)
{
q = (struct pcb *)malloc(sizeof(struct pcb));
scanf("%s", &(q->name));
scanf("%d", &(q->needtime));
q->cputime = 0; // 初始化cpu使用时间
q->round = 0; // 初始化时间片使用次数
q->count = 0; // 记录每个进程被调度次数的变量
q->process = ready; // 就绪
q->next = NULL; // 下一节点为NULL
if (i == 0)
{ // 第一个进程,初始化链表头指针 p 和 t
p = q;
t = q;
}
else
{
t->next = q;
t = q;
}
i++;
} /*while*/
// q1(p)-->q2-->q3-->q4(t)
return p;
}
void cpu_round(struct pcb *q) /*处理机轮转*/
{
// 时间片为2
q->cputime += 2;
q->needtime -= 2;
if (q->needtime < 0)
// 解决needtime为1的问题
{
q->needtime = 0;
}
q->count++; // 次数
q->round++;
q->process = execute; // 执行
}
struct pcb *get_next(struct pcb *k, struct pcb *head)
{ /*返回没有结束的进程*/
struct pcb *t;
t = k;
do
{
t = t->next;
} while (t && t->process == finish);
if (t == NULL) // 如果到达链表末尾 从头开始 遍历到找到未完成的进程
{
t = head;
while (t->next != k && t->process == finish)
{
t = t->next;
}
}
return t;
}
void set_state(struct pcb *p)
{ // 更新链表中每个PCB的状态
while (p)
{
if (p->needtime == 0)
{
p->process = finish;
}
if (p->process == execute)
{
p->process = ready; // 如果进程正在执行,将状态设置为 'ready'
}
p = p->next;
}
}
void display_round(struct pcb *p)
{ // 显示当前各个进程的状态和资源使用情况
printf("NAME CPUTIME NEEDTIME COUNT ROUND STATE\n");
while (p)
{
printf("%s", p->name);
printf(" ");
printf("%d", p->cputime);
printf(" ");
printf("%d", p->needtime);
printf(" ");
printf("%d", p->count);
printf(" ");
printf("%d", p->round);
printf(" ");
switch (p->process)
{
case ready:
printf("ready\n");
break;
case execute:
printf("execute\n");
break;
case finish:
printf("finish\n");
break;
}
p = p->next;
}
}
void round_cal()
{ /*循环轮转调度*/
struct pcb *p;
struct pcb *r;
int cpu = 0; // 累计执行时间
// 轮转进程建立
p = get_process_round();
r = p;
while (!process_finish(p)) // 判断进程是否结束
{
cpu += 2;
cpu_round(r); // 处理当前的轮转
r = get_next(r, p); // 返回没有结束的进程
printf("cpu %d\n", cpu);
display_round(p); // 显示当前各个进程的状态和资源使用情况
set_state(p); // 更新链表中每一个PCB的状态
sleep(5);
}
printf("All processes have finished,press any key to exit");
getch();
}
/* 主程序 */
void main()
{
int user_input;
display_menu();
scanf("%d", &user_input);
switch (user_input)
{
case 1:
priority_cal();
break;
case 2:
round_cal();
break;
case 3:
break;
default:
display_menu();
scanf("%d", &user_input);
break;
}
}