4.22实验一:进程调度模拟算法
实验一:进程调度模拟算法
一、实验目的
进程调度是处理机管理的核心内容。本实验要求用高级语言编写模拟进程调度程序,以便加深理解有关进程控制快、进程队列等概念,并体会和了解优先数算法和时间片轮转算法的具体实施办法。
二、实验要求
1.设计进程控制块 PCB 的结构,通常应包括如下信息:进程名、进程优先数(或轮转时间片数)、进程已占用的CPU时间、进程到完成还需要的时间、进程的状态、当前队列指针等。
2.编写两种调度算法程序:
优先数调度算法程序
循环轮转调度算法程序
3.按要求输出结果。
提示和说明:
分别用两种调度算法对伍个进程进行调度。每个进程可有三种状态;执行状态(RUN)、就绪状态(READY包括等待状态)和完成状态(FINISH),并假定初始状态为就绪状态。
(一)进程控制块结构如下:
NAME--进程标示符
PRIO/ROUND--进程优先数/进程每次轮转的时间片数(设为常数2)
CPUTIME--进程累计占用CPU 的时间片数
NEEDTIMI--进程到完成还需要的时间片数
STATE--进程状态
NEXT--链指针
注:
1.为了便于处理,程序中进程的的运行时间以时间片为单位进行计算:
2.各进程的优先数或轮转时间片数,以及进程运行时间片数的初值,均由用户在程序运行时给定。
(二)进程的就绪态和等待态均为链表结构,共有四个指针如下:
RUN--当前运行进程指针
READY--就需队列头指针
TAIL-- 就需队列尾指针
FINISH-完成队列头指针
(三)程序说明
1.在优先数算法中,进程优先数的初值设为:
50-NEEDTIME
每执行一次,优先数减1,CPU 时间片数加1,进程还需要的时间片数减1。在轮转法中,采用固定时间片单位(两个时间片为一个单位),进程每轮转一次,CPU时间片数加2,进程还需要的时间片数减2,并退出CPU,排到就绪队列尾,等待下一次调度。
2.程序的模块结构提示如下:
整个程序可由主程序和如下7个过程组成:
(1)INSERT1--在优先数算法中,将尚未完成的PCB 按优先数顺序插入到就绪队列
中;(2)INSERT2--在轮转法中,将执行了一个时间片单位(为2),但尚未完成的进程的PCB,插到就绪队列的队尾;
(3)FIRSTIN--调度就绪队列的第一个进程投入运行;
(4)PRINT--显示每执行一次后所有进程的状态及有关信息,
(5)CREATE--创建新进程,并将它的PCB插入就绪队列;
(6)PRISCH--按优先数算法调度进程;
(7)ROUNDSCH--按时间片轮转法调度进程。
主程序定义 PCB 结构和其他有关变量。
(四)运行和显示
程序开始运行后,首先提示:请用户选择算法,输入进程名和相应的NEEDTIME值。每次显示结果均为如下5个字段:
name cputime needtime priority state
注:
1.在 state 字段中,"R"代表执行态,"W"代表就绪(等待)态,"F"代表完成态2.应先显示"R"态的,再显示"W"态的,再显示"F"态的。
3.在"W"态中,以优先数高低或轮转顺序排队;在"F"态中,以完成先后顺序排队。
三、实验过程
1.准备
A. 查阅相关资料:
研究了进程调度的基本概念和原理
学习了优先数调度算法和时间片轮转算法的实现方式
查阅了C++中链表操作和指针使用的相关资料
参考了操作系统教材中关于进程控制块(PCB)的设计
- 初步编写程序:
设计了PCB结构体,包含进程名、优先数、CPU时间等字段
编写了两种调度算法的框架
实现了进程队列的基本操作(插入、删除等)
设计了状态显示函数
C. 准备测试数据:
进程名 需要时间片数
P1 5
P2 8
P3 5
2.上机调试
首先测试优先数调度算法
验证进程状态转换是否正确
检查队列操作是否正常
测试时间片轮转算法
比较两种算法的输出结果差异
调整时间片大小观察调度变化
3. 主要流程和源代码
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <cstdlib> // 用于 system("pause")
using namespace std;
// 进程状态枚举
enum ProcessState {
STATE_RUN, // 执行态
STATE_READY, // 就绪态
STATE_FINISH // 完成态
};
// 进程控制块结构
struct PCB {
string name; // 进程名
int prio; // 优先数
int round; // 轮转时间片数
int cpuTime; // 已占用CPU时间
int needTime; // 还需要的时间
ProcessState state; // 进程状态
PCB* next; // 链指针
PCB(string n, int nt) : name(n), needTime(nt), cpuTime(0), state(STATE_READY), next(nullptr) {
prio = 50 - needTime; // 初始优先数
round = 2; // 固定时间片单位
}
};
// 全局指针
PCB* currentRun = nullptr; // 当前运行进程
PCB* readyQueue = nullptr; // 就绪队列头
PCB* tailQueue = nullptr; // 就绪队列尾
PCB* finishQueue = nullptr; // 完成队列头
// 函数声明
void createProcesses();
void printProcesses();
void prisch(); // 优先数调度
void roundsch(); // 轮转调度
void firstin();
void insert1(PCB* p); // 优先数算法的插入
void insert2(PCB* p); // 轮转算法的插入
int main() {
int choice;
cout << "请选择调度算法 (1-优先数, 2-时间片轮转): ";
cin >> choice;
// 创建进程
createProcesses();
// 根据选择执行不同调度算法
if (choice == 1) {
cout << "\n优先数调度算法:\n";
while (currentRun != nullptr || readyQueue != nullptr) {
prisch();
printProcesses();
}
} else if (choice == 2) {
cout << "\n时间片轮转调度算法:\n";
while (currentRun != nullptr || readyQueue != nullptr) {
roundsch();
printProcesses();
}
} else {
cout << "无效选择!" << endl;
}
// 打印最终完成队列
cout << "\n所有进程已完成:\n";
printProcesses();
// 暂停程序,防止闪退
cout << "\n按任意键继续..." << endl;
cin.ignore(); // 忽略之前输入留下的换行符
cin.get(); // 等待用户输入
return 0;
}
// 创建进程
void createProcesses() {
int numProcesses;
cout << "输入进程数量: ";
cin >> numProcesses;
for (int i = 0; i < numProcesses; ++i) {
string name;
int needTime;
cout << "输入进程名和需要的时间片数 (例如 P1 10): ";
cin >> name >> needTime;
PCB* p = new PCB(name, needTime);
if (readyQueue == nullptr) {
readyQueue = p;
tailQueue = p;
} else {
tailQueue->next = p;
tailQueue = p;
}
}
}
// 打印所有进程状态
void printProcesses() {
cout << "\nname\tcputime\tneedtime\tpriority\tstate\n";
cout << "---------------------------------------------\n";
// 打印运行中的进程
if (currentRun != nullptr) {
cout << currentRun->name << "\t" << currentRun->cpuTime << "\t" << currentRun->needTime << "\t\t"
<< currentRun->prio << "\t\t" << "R" << endl;
}
// 打印就绪队列中的进程
PCB* p = readyQueue;
while (p != nullptr) {
cout << p->name << "\t" << p->cpuTime << "\t" << p->needTime << "\t\t"
<< p->prio << "\t\t" << "W" << endl;
p = p->next;
}
// 打印完成队列中的进程
p = finishQueue;
while (p != nullptr) {
cout << p->name << "\t" << p->cpuTime << "\t" << p->needTime << "\t\t"
<< p->prio << "\t\t" << "F" << endl;
p = p->next;
}
cout << endl;
}
// 优先数调度算法
void prisch() {
if (currentRun != nullptr) {
// 当前进程执行一个时间片
currentRun->cpuTime++;
currentRun->needTime--;
currentRun->prio--;
if (currentRun->needTime == 0) {
// 进程完成
currentRun->state = STATE_FINISH;
currentRun->next = finishQueue;
finishQueue = currentRun;
currentRun = nullptr;
} else {
// 重新插入就绪队列
PCB* temp = currentRun;
currentRun = nullptr;
insert1(temp);
}
}
// 从就绪队列中选择优先数最高的进程运行
if (currentRun == nullptr && readyQueue != nullptr) {
firstin();
}
}
// 轮转调度算法
void roundsch() {
if (currentRun != nullptr) {
// 当前进程执行一个时间片单位(2个时间片)
currentRun->cpuTime += 2;
currentRun->needTime -= 2;
if (currentRun->needTime <= 0) {
// 进程完成
currentRun->needTime = 0;
currentRun->state = STATE_FINISH;
currentRun->next = finishQueue;
finishQueue = currentRun;
currentRun = nullptr;
} else {
// 重新插入就绪队列尾部
PCB* temp = currentRun;
currentRun = nullptr;
insert2(temp);
}
}
// 从就绪队列中选择下一个进程运行
if (currentRun == nullptr && readyQueue != nullptr) {
firstin();
}
}
// 将就绪队列的第一个进程投入运行
void firstin() {
currentRun = readyQueue;
readyQueue = readyQueue->next;
currentRun->next = nullptr;
currentRun->state = STATE_RUN;
// 更新队尾指针
if (readyQueue == nullptr) {
tailQueue = nullptr;
}
}
// 优先数算法的插入(按优先数排序)
void insert1(PCB* p) {
p->state = STATE_READY;
if (readyQueue == nullptr) {
readyQueue = p;
tailQueue = p;
} else {
PCB* prev = nullptr;
PCB* current = readyQueue;
// 找到插入位置(按优先数从高到低)
while (current != nullptr && current->prio >= p->prio) {
prev = current;
current = current->next;
}
if (prev == nullptr) {
// 插入到队首
p->next = readyQueue;
readyQueue = p;
} else {
// 插入到中间或队尾
prev->next = p;
p->next = current;
if (current == nullptr) {
tailQueue = p;
}
}
}
}
// 轮转算法的插入(插入到队尾)
void insert2(PCB* p) {
p->state = STATE_READY;
if (readyQueue == nullptr) {
readyQueue = p;
tailQueue = p;
} else {
tailQueue->next = p;
tailQueue = p;
p->next = nullptr;
}
}
4.遇到的主要问题和解决方法
A. :程状态显示混乱,特别是完成队列的顺序不正确,重新设计状态显示逻辑
确保先显示运行态,再显示就绪态,最后显示完成态
在完成队列中按完成顺序排列进程
四、实验结果
五、实验总结
学到了操作系统进程调度的核心原理,深入理解了优先数算法和时间片轮转算法的设计思想与实现方式,对操作系统的进程管理机制有了更直观的认识。了解了进程控制块(PCB)的数据结构设计,掌握了通过链表管理进程队列的方法,熟悉了进程状态转换(就绪、运行、完成)的实现逻辑。握了使用C++实现复杂算法的技巧,提高了分析问题和设计解决方案的能力。