#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <iomanip>
#include <string>
using namespace std;
// 进程状态枚举
enum ProcessState {
READY,
RUNNING,
BLOCKED,
FINISHED
};
// 片段类型枚举
enum SegmentType {
CPU_SEGMENT,
IO_SEGMENT
};
// 进程片段结构体
struct Segment {
SegmentType type;
int length;
int remaining; // 剩余执行时间
Segment(SegmentType t, int len) : type(t), length(len), remaining(len) {}
};
// 进程结构体
struct Process {
int id;
int priority;
int arrivalTime;
vector<Segment> segments;
int currentSegment; // 当前执行的片段索引
// 统计信息
int finishTime;
int timeSliceUsed;
int readyWaitTime;
int IOWaitTime;
int CPUTime;
int IOTime;
int turnaroundTime;
double weightedTurnaroundTime;
ProcessState state;
int remainingTimeSlice; // 当前时间片剩余时间
Process(int id, int pri, int arr, const vector<Segment>& segs)
: id(id), priority(pri), arrivalTime(arr), segments(segs),
currentSegment(0), finishTime(0), timeSliceUsed(0),
readyWaitTime(0), IOWaitTime(0), CPUTime(0), IOTime(0),
turnaroundTime(0), weightedTurnaroundTime(0.0),
state(READY), remainingTimeSlice(0) {
}
};
// 系统统计结构体
struct SystemStats {
int totalProcesses;
int timeSlice;
int totalCPUTime;
int totalIOTime;
double avgReadyWaitTime;
double avgIOWaitTime;
double avgCPUTime;
double avgIOTime;
double avgTurnaroundTime;
double avgWeightedTurnaroundTime;
};
class Scheduler {
private:
vector<Process> processes;
int timeSlice;
int currentTime;
queue<int> readyQueue; // 存储进程ID
queue<int> ioQueue; // 存储进程ID
vector<int> finishedProcesses; // 存储已完成进程ID
Process* currentProcess; // 当前运行的进程
bool cpuBusy;
bool ioBusy;
Process* ioProcess; // 当前使用IO设备的进程
SystemStats stats;
public:
Scheduler(const vector<Process>& procs, int ts)
: processes(procs), timeSlice(ts), currentTime(0),
currentProcess(nullptr), cpuBusy(false), ioBusy(false), ioProcess(nullptr) {
// 初始化统计信息
stats.totalProcesses = procs.size();
stats.timeSlice = ts;
stats.totalCPUTime = 0;
stats.totalIOTime = 0;
// 按到达时间排序进程
sort(processes.begin(), processes.end(),
[](const Process& a, const Process& b) {
return a.arrivalTime < b.arrivalTime;
});
// 初始化就绪队列
for (int i = 0; i < processes.size(); i++) {
if (processes[i].arrivalTime <= currentTime) {
readyQueue.push(i);
}
}
}
// 简单轮转调度 - 主调度循环
// 这是整个调度系统的核心,采用时间驱动的方式模拟进程调度
void roundRobinScheduling() {
// 主循环:持续运行直到所有进程都完成
while (!allProcessesFinished()) {
// 检查是否有新进程到达(到达时间等于当前时间)
checkNewArrivals();
// IO设备处理:处理正在使用IO的进程,以及从IO队列中取出新进程
processIO();
// CPU调度:处理当前运行的进程,以及从就绪队列中调度新进程
scheduleCPU();
// 时间推进:每个时钟周期时间加1
currentTime++;
// 更新等待时间统计:增加就绪队列和IO队列中进程的等待时间
updateWaitTimes();
}
// 所有进程完成后,计算最终统计信息(平均等待时间、周转时间等)
calculateStatistics();
}
private:
bool allProcessesFinished() {
return finishedProcesses.size() == processes.size();
}
// 检查新到达的进程 - 每个时钟周期调用一次
// 将到达时间等于当前时间的进程加入就绪队列
void checkNewArrivals() {
for (int i = 0; i < processes.size(); i++) {
// 检查进程是否在当前时刻到达且处于就绪状态
if (processes[i].arrivalTime == currentTime &&
processes[i].state == READY) {
readyQueue.push(i); // 加入就绪队列,等待CPU调度
}
}
}
// IO设备处理函数 - 模拟IO设备的执行
void processIO() {
// 第一部分:处理当前正在使用IO设备的进程
if (ioBusy && ioProcess) {
Segment& currentSegment = ioProcess->segments[ioProcess->currentSegment];
// 执行一个时间单位的IO操作
currentSegment.remaining--; // IO片段剩余时间减1
ioProcess->IOTime++; // 进程总IO时间加1
stats.totalIOTime++; // 系统总IO时间加1
// 检查IO片段是否完成
if (currentSegment.remaining == 0) {
ioProcess->currentSegment++; // 移动到下一个片段
// 情况1:所有片段都完成,进程结束
if (ioProcess->currentSegment >= ioProcess->segments.size()) {
ioProcess->state = FINISHED;
ioProcess->finishTime = currentTime;
finishedProcesses.push_back(ioProcess->id);
}
// 情况2:还有下一个片段,IO完成后需要CPU处理,进入就绪队列
else {
// IO完成后,下一个片段通常是CPU片段,进入就绪队列等待CPU调度
ioProcess->state = READY;
readyQueue.push(findProcessIndex(ioProcess->id));
}
// IO设备释放
ioBusy = false;
ioProcess = nullptr;
}
}
// 第二部分:如果IO设备空闲,从IO队列中取出下一个等待IO的进程
// IO设备也采用FIFO队列,先到先服务
if (!ioBusy && !ioQueue.empty()) {
int nextIOIndex = ioQueue.front(); // 取队列头部进程
ioQueue.pop();
Process& nextProcess = processes[nextIOIndex];
nextProcess.state = BLOCKED; // 设置为阻塞状态(正在使用IO)
ioProcess = &nextProcess;
ioBusy = true; // IO设备被占用
}
}
// CPU调度核心函数 - 实现轮转调度算法
void scheduleCPU() {
// 第一部分:处理当前正在运行的进程
if (cpuBusy && currentProcess) {
Segment& currentSegment = currentProcess->segments[currentProcess->currentSegment];
// 执行一个时间单位的CPU操作
currentSegment.remaining--; // 当前片段剩余时间减1
currentProcess->CPUTime++; // 进程总CPU时间加1
currentProcess->remainingTimeSlice--; // 当前时间片剩余时间减1
stats.totalCPUTime++; // 系统总CPU时间加1
// 情况1:当前CPU片段执行完成
if (currentSegment.remaining == 0) {
currentProcess->currentSegment++; // 移动到下一个片段
// 情况1.1:所有片段都完成,进程结束
if (currentProcess->currentSegment >= currentProcess->segments.size()) {
currentProcess->state = FINISHED;
currentProcess->finishTime = currentTime; // 记录完成时间
finishedProcesses.push_back(currentProcess->id);
cpuBusy = false;
currentProcess = nullptr;
}
// 情况1.2:还有下一个片段,根据片段类型决定去向
else {
Segment& nextSegment = currentProcess->segments[currentProcess->currentSegment];
if (nextSegment.type == IO_SEGMENT) {
// 下一个是IO片段,进入IO阻塞队列
currentProcess->state = BLOCKED;
ioQueue.push(findProcessIndex(currentProcess->id));
}
else {
// 下一个是CPU片段,进入就绪队列等待再次调度
currentProcess->state = READY;
readyQueue.push(findProcessIndex(currentProcess->id));
}
cpuBusy = false;
currentProcess = nullptr;
}
}
// 情况2:时间片用完但片段未完成(轮转调度的关键)
else if (currentProcess->remainingTimeSlice == 0) {
// 强制让出CPU,重新进入就绪队列末尾,等待下次调度
currentProcess->state = READY;
readyQueue.push(findProcessIndex(currentProcess->id));
cpuBusy = false;
currentProcess = nullptr;
}
}
// 第二部分:如果CPU空闲,从就绪队列中取出下一个进程执行
// 这是轮转调度的核心:FIFO队列,公平分配CPU时间
if (!cpuBusy && !readyQueue.empty()) {
int nextIndex = readyQueue.front(); // 取队列头部进程(FIFO)
readyQueue.pop();
Process& nextProcess = processes[nextIndex];
nextProcess.state = RUNNING; // 设置为运行状态
nextProcess.remainingTimeSlice = timeSlice; // 分配完整时间片
nextProcess.timeSliceUsed++; // 记录使用的时间片数量
currentProcess = &nextProcess;
cpuBusy = true;
}
}
// 更新等待时间统计 - 每个时钟周期调用一次
// 统计进程在就绪队列和IO队列中的等待时间,用于性能分析
void updateWaitTimes() {
// 更新就绪队列中所有进程的CPU等待时间
// 这些进程正在等待CPU资源,每过一个时间单位等待时间加1
queue<int> tempQueue = readyQueue;
while (!tempQueue.empty()) {
int procIndex = tempQueue.front();
tempQueue.pop();
processes[procIndex].readyWaitTime++; // CPU等待时间递增
}
// 更新IO队列中所有进程的IO等待时间
// 这些进程正在等待IO设备资源,每过一个时间单位等待时间加1
queue<int> tempIOQueue = ioQueue;
while (!tempIOQueue.empty()) {
int procIndex = tempIOQueue.front();
tempIOQueue.pop();
processes[procIndex].IOWaitTime++; // IO等待时间递增
}
}
// 根据进程ID查找进程在数组中的索引
// 由于队列中存储的是索引而不是进程对象,需要此函数进行转换
int findProcessIndex(int id) {
for (int i = 0; i < processes.size(); i++) {
if (processes[i].id == id) {
return i;
}
}
return -1; // 未找到返回-1(理论上不应该发生)
}
// 计算统计信息 - 在所有进程完成后调用
// 计算每个进程和系统的平均性能指标
void calculateStatistics() {
double totalReadyWait = 0;
double totalIOWait = 0;
double totalCPUTime = 0;
double totalIOTime = 0;
double totalTurnaround = 0;
double totalWeightedTurnaround = 0;
// 遍历所有进程,计算各项指标
for (Process& proc : processes) {
// 周转时间 = 完成时间 - 到达时间(进程从到达到最后完成的总时间)
proc.turnaroundTime = proc.finishTime - proc.arrivalTime;
// 带权周转时间 = 周转时间 / 服务时间(CPU时间 + IO时间)
// 反映进程等待时间相对于执行时间的比例,值越小说明调度效率越高
proc.weightedTurnaroundTime = static_cast<double>(proc.turnaroundTime) /
(proc.CPUTime + proc.IOTime);
// 累加各项指标用于计算平均值
totalReadyWait += proc.readyWaitTime;
totalIOWait += proc.IOWaitTime;
totalCPUTime += proc.CPUTime;
totalIOTime += proc.IOTime;
totalTurnaround += proc.turnaroundTime;
totalWeightedTurnaround += proc.weightedTurnaroundTime;
}
// 计算系统平均指标
stats.avgReadyWaitTime = totalReadyWait / processes.size();
stats.avgIOWaitTime = totalIOWait / processes.size();
stats.avgCPUTime = totalCPUTime / processes.size();
stats.avgIOTime = totalIOTime / processes.size();
stats.avgTurnaroundTime = totalTurnaround / processes.size();
stats.avgWeightedTurnaroundTime = totalWeightedTurnaround / processes.size();
}
public:
void writeResultsToFile(const string& filename) {
ofstream outFile(filename);
if (!outFile) {
cerr << "无法打开输出文件: " << filename << endl;
return;
}
// 按结束时间排序进程
vector<Process> sortedProcesses = processes;
sort(sortedProcesses.begin(), sortedProcesses.end(),
[](const Process& a, const Process& b) {
return a.finishTime < b.finishTime;
});
// 写入第一行(对齐格式)
outFile << "Processes: " << setw(3) << right << stats.totalProcesses
<< " TimeSlice: " << setw(3) << right << stats.timeSlice << endl;
// 写入每个进程的信息(对齐格式)
for (const Process& proc : sortedProcesses) {
// 计算CPU和IO片段数量
int cpuPieces = 0;
int ioPieces = 0;
for (const Segment& seg : proc.segments) {
if (seg.type == CPU_SEGMENT) {
cpuPieces++;
} else {
ioPieces++;
}
}
outFile << "ID " << setw(2) << right << proc.id << ": ";
outFile << "Priority: " << setw(4) << right << proc.priority << ", ";
outFile << "Arrival: " << setw(4) << right << proc.arrivalTime << ", ";
outFile << "Finish: " << setw(5) << right << proc.finishTime << ", ";
outFile << "CPU pieces: " << setw(2) << right << cpuPieces << ", ";
outFile << "IO pieces: " << setw(2) << right << ioPieces << ", ";
outFile << "CPU wait: " << setw(4) << right << proc.readyWaitTime << ", ";
outFile << "CPU: " << setw(3) << right << proc.CPUTime << ", ";
outFile << "IO wait: " << setw(5) << right << proc.IOWaitTime << ", ";
outFile << "IO: " << setw(4) << right << proc.IOTime << ", ";
outFile << "Turnover: " << setw(5) << right << proc.turnaroundTime << ", ";
outFile << "Weighted turnover: " << fixed << setprecision(3)
<< setw(7) << right << proc.weightedTurnaroundTime << endl;
}
// 写入统计信息(对齐格式)
outFile << "Average CPU wait: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgReadyWaitTime << ", ";
outFile << "Average CPU: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgCPUTime << ", ";
outFile << "Average IO wait: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgIOWaitTime << ", ";
outFile << "Average IO: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgIOTime << ", ";
outFile << "Average turnover: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgTurnaroundTime << ", ";
outFile << "Average weighted turnover: " << fixed << setprecision(3)
<< setw(8) << right << stats.avgWeightedTurnaroundTime << endl;
outFile.close();
}
void printStatistics() {
cout << "\n=== 调度统计结果 ===" << endl;
cout << "进程数量: " << stats.totalProcesses << endl;
cout << "时间片大小: " << stats.timeSlice << endl;
cout << "平均就绪等待时间: " << fixed << setprecision(2) << stats.avgReadyWaitTime << endl;
cout << "平均IO等待时间: " << stats.avgIOWaitTime << endl;
cout << "平均占用CPU时间: " << stats.avgCPUTime << endl;
cout << "平均占用IO设备时间: " << stats.avgIOTime << endl;
cout << "平均周转时间: " << stats.avgTurnaroundTime << endl;
cout << "平均带权周转时间: " << stats.avgWeightedTurnaroundTime << endl;
}
};
// 读取进程文件 - 从文件中读取进程信息并构建进程列表
// 文件格式:第一行为进程数量n,接下来n行,每行包含:进程ID、优先级、到达时间、片段数量、片段长度列表
vector<Process> readProcessFile(const string& filename) {
ifstream inFile(filename);
vector<Process> processes;
if (!inFile) {
cerr << "无法打开输入文件: " << filename << endl;
return processes;
}
int n; // 进程数量
inFile >> n;
// 读取每个进程的信息
for (int i = 0; i < n; i++) {
int id, priority, arrivalTime, m; // m为片段数量
inFile >> id >> priority >> arrivalTime >> m;
vector<Segment> segments;
// 读取进程的片段序列:偶数索引为CPU片段,奇数索引为IO片段
// 这种交替模式模拟了典型的进程执行模式:CPU计算 -> IO操作 -> CPU计算 -> ...
for (int j = 0; j < m; j++) {
int segmentLength;
inFile >> segmentLength;
SegmentType type = (j % 2 == 0) ? CPU_SEGMENT : IO_SEGMENT;
segments.push_back(Segment(type, segmentLength));
}
// 创建进程对象并加入列表
processes.push_back(Process(id, priority, arrivalTime, segments));
}
inFile.close();
return processes;
}
int main() {
// 读取进程数据
vector<Process> processes = readProcessFile("TASK");
if (processes.empty()) {
cerr << "没有读取到进程数据,程序退出" << endl;
return 1;
}
int choice;
bool running = true;
while (running) {
cout << "\n========== 进程调度系统 ==========" << endl;
cout << "1. 输入时间片并运行调度" << endl;
cout << "2. 退出程序" << endl;
cout << "请选择操作(输入 1 或 2): ";
cin >> choice;
if (choice == 1) {
// 用户输入时间片大小
int timeSlice;
cout << "\n请输入时间片大小(范围:5-20): ";
cin >> timeSlice;
// 验证时间片大小是否在有效范围内
while (timeSlice < 5 || timeSlice > 20) {
cout << "输入无效!时间片大小必须在 5-20 之间,请重新输入: ";
cin >> timeSlice;
}
cout << "\n=== 使用时间片大小: " << timeSlice << " 进行调度 ===" << endl;
// 重新读取进程数据以重置状态
vector<Process> freshProcesses = readProcessFile("TASK");
if (freshProcesses.empty()) {
cerr << "无法重新读取进程数据" << endl;
continue;
}
// 创建调度器并执行调度
// 使用新的进程数据和时间片大小初始化调度器
Scheduler scheduler(freshProcesses, timeSlice);
// 执行轮转调度算法,直到所有进程完成
scheduler.roundRobinScheduling();
// 输出结果到文件
scheduler.writeResultsToFile("ROUND");
// 打印统计信息
scheduler.printStatistics();
cout << "\n调度完成!结果已保存到 ROUND文件。" << endl;
}
else if (choice == 2) {
cout << "\n感谢使用,程序退出!" << endl;
running = false;
}
else {
cout << "\n输入无效!请输入 1 或 2。" << endl;
}
}
return 0;
}请根据此代码,帮我生成多组测试数据,使其具有代表性
最新发布