优先级调度算法(Priority Scheduling)是操作系统调度中一种常见的调度策略,它通过为每个进程分配一个优先级,调度时选择优先级最高的进程执行。优先级调度可以分为非抢占式和抢占式两种方式。
- 非抢占式优先级调度:当一个进程正在执行时,只有它自己结束或者进入阻塞状态,才会让出 CPU,调度器才会选择其他进程。
- 抢占式优先级调度:如果一个新的进程的优先级更高,当前正在执行的进程会被抢占,新的进程会获得 CPU 执行。
在本例中,我们将实现 非抢占式优先级调度。
算法步骤:
- 输入进程的到达时间、执行时间和优先级。
- 根据优先级排序进程,优先级高的进程先执行。
- 计算每个进程的等待时间:等待时间 = 当前进程开始执行的时间 - 到达时间。
- 计算每个进程的周转时间:周转时间 = 进程结束时间 - 到达时间。
- 计算平均等待时间和平均周转时间。
C++实现非抢占式优先级调度算法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Process {
int id; // 进程ID
int arrival; // 到达时间
int burst; // 服务时间(CPU时间)
int priority; // 优先级
int start; // 开始时间
int finish; // 结束时间
int waiting; // 等待时间
int turnaround; // 周转时间
};
// 按优先级排序
bool comparePriority(Process a, Process b) {
return a.priority < b.priority; // 优先级越小,越高
}
// 优先级调度算法(非抢占式)
void priorityScheduling(vector<Process>& processes) {
int currentTime = 0;
// 按优先级排序(优先级越低越先执行)
sort(processes.begin(), processes.end(), comparePriority);
for (int i = 0; i < processes.size(); ++i) {
Process& p = processes[i];
// 如果当前时间小于进程到达时间,更新当前时间
if (currentTime < p.arrival) {
currentTime = p.arrival;
}
// 计算进程的开始时间、结束时间、等待时间、周转时间
p.start = currentTime;
p.finish = p.start + p.burst;
p.waiting = p.start - p.arrival;
p.turnaround = p.finish - p.arrival;
// 更新当前时间
currentTime = p.finish;
}
}
// 打印调度结果
void printResults(const vector<Process>& processes) {
cout << "ID\tArrival\tBurst\tPriority\tStart\tFinish\tWaiting\tTurnaround" << endl;
for (const auto& p : processes) {
cout << p.id << "\t"
<< p.arrival << "\t"
<< p.burst << "\t"
<< p.priority << "\t\t"
<< p.start << "\t"
<< p.finish << "\t"
<< p.waiting << "\t"
<< p.turnaround << endl;
}
}
// 计算平均等待时间和平均周转时间
void calculateAverages(const vector<Process>& processes) {
double totalWaiting = 0;
double totalTurnaround = 0;
for (const auto& p : processes) {
totalWaiting += p.waiting;
totalTurnaround += p.turnaround;
}
cout << "\nAverage Waiting Time: " << totalWaiting / processes.size() << endl;
cout << "Average Turnaround Time: " << totalTurnaround / processes.size() << endl;
}
int main() {
vector<Process> processes = {
{1, 0, 5, 2}, // 进程1:到达时间0,服务时间5,优先级2
{2, 1, 3, 1}, // 进程2:到达时间1,服务时间3,优先级1
{3, 2, 8, 3}, // 进程3:到达时间2,服务时间8,优先级3
{4, 3, 6, 2}, // 进程4:到达时间3,服务时间6,优先级2
};
// 执行优先级调度算法
priorityScheduling(processes);
// 打印每个进程的调度结果
printResults(processes);
// 计算平均等待时间和平均周转时间
calculateAverages(processes);
return 0;
}
代码解析:
- Process结构体:每个进程包含进程ID、到达时间、服务时间(CPU时间)、优先级、开始时间、结束时间、等待时间和周转时间。
comparePriority
函数:该函数按优先级排序,优先级越小的进程越早执行(可以按需求调整)。priorityScheduling
函数:实现非抢占式优先级调度,按照优先级排序进程,并计算每个进程的开始时间、结束时间、等待时间和周转时间。printResults
函数:打印每个进程的调度结果,包括进程ID、到达时间、服务时间、优先级、开始时间、结束时间、等待时间和周转时间。calculateAverages
函数:计算所有进程的平均等待时间和平均周转时间。
输出示例:
ID Arrival Burst Priority Start Finish Waiting Turnaround
2 1 3 1 1 4 0 3
1 0 5 2 4 9 4 9
4 3 6 2 9 15 6 12
3 2 8 3 15 23 13 21
Average Waiting Time: 7.25
Average Turnaround Time: 11.25
解释:
- 进程 2 优先级最高(1),所以它先执行,开始时间是1,结束时间是4。
- 进程 1 和进程 4 的优先级相同,因此它们按照到达时间先后顺序执行。进程 1 在进程 2 完成后执行,开始时间为4,结束时间为9。进程 4 紧随其后,开始时间为9,结束时间为15。
- 最后进程 3 最后执行。
总结:
- 优先级调度算法是根据每个进程的优先级来决定执行顺序的。
- 非抢占式优先级调度的优点是简单、容易理解,但缺点是可能出现饥饿现象,即低优先级的进程可能一直得不到执行。
- 本示例实现了一个简单的非抢占式优先级调度,适用于一些简单的调度场景。在实际应用中,操作系统常常采用改进的优先级调度算法,如带有老化机制的优先级调度,以避免饥饿现象。