C++模拟进程的三状态模型和进程调度(FCFS)性能计算
不多BB 直接上代码
main.cpp文件
//main.cpp
#include "Basic_function.h"
#include "State_transition.h"
//关键词:进程三模型状态模拟 进程调度(FCFS)性能计算
using namespace std;
typedef unsigned int uint;
uint cur_time; //时间线
uint CPU_size; //几核CPU
uint IO1_equipment_size; //几个IO1设备
uint IO2_equipment_size; //几个IO2设备
double turnover_time_sum; //所有进程周转时间之和
double weighted_turnover_time_sum; //所有进程带权周转时间之和
vector<PCB> CPU; //处理机
vector<PCB> IO1_equipment; //IO1设备
vector<PCB> IO2_equipment; //IO2设备
vector<PCB> destroy; //待销毁
queue<PCB> ready_que; //就绪队列
queue<PCB> block_IO1_que; //请求IO1设备阻塞队列
queue<PCB> block_IO2_que; //请求IO2设备阻塞队列
bool cmp(PCB &a,PCB &b){ //先来先进内存(就绪队列)
return a.get_arrive_time()<b.get_arrive_time();
}
void READY_TO_CPU(){
while(ready_to_CPU());//ready就绪队列里面的进程上处理机运行
while(scan_CPU()) while(ready_to_CPU()); //扫描CPU 看是否需要有变动(有进程下CPU) 如果有的话继续让ready就绪队列上CPU
//至于这里为什么在 while()whiel(); 语句前面还需要一个while语句 是因为可能会出现这种情况:
//“当前的还有空闲的CPU,而ready就绪队列里面又刚好到了新的就绪进程,但是不巧的是没有需要下CPU的进程”
//BLOCK_QUE_TO_IO函数同理
}
void BLOCK_QUE_TO_IO(){
while(block_que_to_IO(1)); //block就绪队列里面的进程上IO1设备进行IO操作
while(scan_IO_equipment(1)) while(block_que_to_IO(1)); //扫描IO1设备 看是否需要有变动(有进程下IO1设备) 如果有的话继续让block就绪队列上IO1设备
while(block_que_to_IO(2));//block就绪队列里面的进程上IO2设备进行IO操作
while(scan_IO_equipment(2)) while(block_que_to_IO(2)); //扫描IO2设备 看是否需要有变动(有进程下IO2设备) 如果有的话继续让block就绪队列上IO2设备
}
int main() { //模拟开始
printf("请输入CPU个数(同时可以跑几个进程):");
cin>>CPU_size;
printf("请输入分别有几台IO1设备、IO2设备:");
cin>>IO1_equipment_size>>IO2_equipment_size;
printf("请输入本次模拟的总进程数目:");
uint num;cin>>num;
vector<PCB> tmp;
for(uint i=0;i<num;i++) tmp.push_back(createProgress(i));
sort(tmp.begin(),tmp.end(),cmp); //按照到达时间排序
cur_time=0; //初始化时间线
turnover_time_sum=weighted_turnover_time_sum=0.0; //初始化 总的周转时间和带权周转时间
while(tmp.size() || CPU.size() || ready_que.size() || IO1_equipment.size() || IO2_equipment.size() ||block_IO1_que.size() || block_IO2_que.size()){
while(tmp.size() && tmp[0].get_arrive_time()==cur_time){ //有进程到了就从后备队列调入内存(就绪队列)
PCB &t=tmp[0];
ready_que.push(t);
tmp.erase(tmp.begin());
}
READY_TO_CPU(); //保证:运行完毕的进程下CPU 就绪队列进程上CPU **************1
BLOCK_QUE_TO_IO(); //保证:IO完毕的进程下IO设备 等待IO的阻塞队列进程上IO ****2
printProgresses(); //打印进程信息
destroyProgresses(); //销毁进程
cur_time++; //全程序的"key"--时间线推移,只有它才能推动这次模拟在逻辑上的运行!!!
CPU_runProgresses(); //模拟CPU跑运行进程
ready_wait(); //模拟就绪队列的等待
use_IO_equipment(); //模拟阻塞进程进行IO
block_wait(); //模拟阻塞队列的等待
READY_TO_CPU(); //保证:运行完毕的进程下CPU 就绪队列进程上CPU **************3
BLOCK_QUE_TO_IO(); //保证:IO完毕的进程下IO设备 等待IO的阻塞队列进程上IO ****4
//只有保证 1 2 cur_time++ 3 4 这样的顺序才可以做到在“离散的时间点”上实现肉眼所见的“时间连续”
}
printProgresses();
destroyProgresses();
printf("\n该次模拟的进程平均周转时间 %.2f, 平均带权周转时间 %.2f\n",turnover_time_sum/num,weighted_turnover_time_sum/num);
//模拟结束
return 0;
}
PCB.h文件
// Created by BingWeiHuang on 2021/4/6.
// 这里是PCB类的声明
// PCB.h
#ifndef SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_PCB_H
#define SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_PCB_H
#include <iostream>
#include <queue>
#include <algorithm>
#include <string>
#include <cstdio>
using namespace std;
typedef unsigned int uint;
extern uint cur_time;
extern uint CPU_size;
extern double turnover_time_sum;
extern double weighted_turnover_time_sum;
class PCB{
private:
uint index; //进程序号
string name; //进程名
string state; //进程状态
uint need_running_time; //预计运行时间
uint arrive_time; //程序到达时间
uint running_time; //实际已经运行的时间
uint end_time; //结束时间
uint waiting_time; //等待时间
public:
bool need_IO1,need_IO2; //是否需要IO1 IO2设备
uint when_need_IO1,when_need_IO2; //在CPU上运行多少时间之后需要请求IO设备
uint IO1_time,IO2_time; //最开始设置的需要IO设备多长时间
uint need_IO1_time,need_IO2_time; //实际上还需要占用IO设备多长时间
bool have_IO1,have_IO2; //是否正在占用IO设备
uint turnover_time()const;//周转时间
double weighted_turnover_time()const;//带权周转时间
void Run();//运行
void Wait();//等待
void End();//结束
void set_state(string new_state);
uint get_arrive_time()const;
uint get_running_time()const;
uint get_need_running_time()const;
void print()const;
PCB(uint inde,string nam,string sta,uint need_running_t,uint arrive_t,bool IO1,bool IO2);
};
#endif //SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_PCB_H
PCB.cpp文件
// 这里是PCB类的实现
// PCB.cpp
#include "PCB.h"
extern uint cur_time;
extern uint CPU_size;
extern double turnover_time_sum;
extern double weighted_turnover_time_sum;
extern vector<PCB> CPU; //处理机
extern queue<PCB> ready_que; //就绪队列
extern queue<PCB> block_IO1_que; //请求IO1设备阻塞队列
extern queue<PCB> block_IO2_que; //请求IO2设备阻塞队列
extern vector<PCB> destroy; //待销毁
using namespace std;
uint PCB::turnover_time()const{ //周转时间
return cur_time-arrive_time;
}
double PCB::weighted_turnover_time()const{ //带权周转时间
return turnover_time()*1.0/running_time;
}
void PCB::Run(){ //运行
running_time++;
}
void PCB::Wait(){ //等待
waiting_time++;
}
void PCB::End(){ //结束
end_time=cur_time;
have_IO1=have_IO2=0;
}
void PCB::set_state(string new_state){
state=new_state;
}
uint PCB::get_arrive_time()const{
return arrive_time;
}
uint PCB::get_running_time()const{
return running_time;
}
uint PCB::get_need_running_time()const{
return need_running_time;
}
void PCB::print()const{
printf("进程%d:\t",index);
cout<<"|名称:"<<name<<"\t";
cout<<"|状态:"<<state<<"\t";
printf("|到达时刻:%4d",arrive_time);
printf("|预计运行时长:%4d",need_running_time);
printf("|已运行总时长:%4d",running_time);
printf("|已等待总时长:%4d|",waiting_time);
if(state=="block"){
if(need_IO1 && have_IO1){
printf("\n\t|已经使用IO1时长:%4d",IO1_time-need_IO1_time);
printf("|还需要使用时长:%4d|",need_IO1_time);
}
else if(need_IO2 && have_IO2){
printf("\n\t|已经使用IO2时长:%4d",IO2_time-need_IO2_time);
printf("|还需要使用时长:%4d|",need_IO2_time);
}
}
else if(state=="destroy"){
printf("\n\t|执行IO的总时长:%4d",turnover_time()-waiting_time-running_time);
printf("|结束时刻:%4d",end_time);
printf("|周转时间:%4d",turnover_time());
printf("|带权周转:%6.2lf|",weighted_turnover_time());
}
cout<<endl;
}
PCB::PCB(uint inde,string nam,string sta,uint need_running_t,uint arrive_t,bool IO1,bool IO2):
index(inde),name(nam),state(sta),need_running_time(need_running_t),arrive_time(arrive_t),need_IO1(IO1),need_IO2(IO2){
running_time=waiting_time=0;
have_IO1=have_IO2=0;
}
State_transition.h文件
// Created by BingWeiHuang on 2021/4/6.
// 这里是关于状态转换的函数的声明
// State_transition.h
#ifndef SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_STATE_TRANSITION_H
#define SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_STATE_TRANSITION_H
#include "PCB.h"
using namespace std;
typedef unsigned int uint;
extern uint cur_time;
extern uint CPU_size;
extern uint IO1_equipment_size;
extern uint IO2_equipment_size;
extern double turnover_time_sum;
extern double weighted_turnover_time_sum;
extern vector<PCB> CPU; //处理机
extern vector<PCB> IO1_equipment; //IO1设备
extern vector<PCB> IO2_equipment; //IO2设备
extern queue<PCB> ready_que; //就绪队列
extern queue<PCB> block_IO1_que; //请求IO1设备阻塞队列
extern queue<PCB> block_IO2_que; //请求IO2设备阻塞队列
extern vector<PCB> destroy; //待销毁
void CPU_to_destroy(int i);//从cpu里面终止进程
void CPU_to_block(uint i,uint num);//等待IO 阻塞
void block_to_ready(uint i,uint num);//已经具备所有资源 唤醒
bool ready_to_CPU();//就绪队列上处理机(FCFS)
void block_to_destroy(uint i,uint num);//有可能出现IO请求被完成之后已经不需要再运行了,为了方便起见我们直接再写一个函数直接终止。
#endif //SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_STATE_TRANSITION_H
State_transition.cpp文件
// 这里是这里是关于状态转换的函数的实现
// State_transition.cpp
#include "State_transition.h"
void CPU_to_destroy(int i){ //从cpu里面终止进程
PCB &t=CPU[i];
t.End();
t.set_state("destroy");
destroy.push_back(t);
CPU.erase(CPU.begin()+i);
}
void CPU_to_block(uint i,uint num){ //等待IO 阻塞
PCB t=CPU[i];
t.set_state("block");
if(num==1){
block_IO1_que.push(t);
}
else if(num==2){
block_IO2_que.push(t);
}
CPU.erase(CPU.begin()+i);
}
void block_to_ready(uint i,uint num){ //已经具备所有资源 唤醒
if(num==1){
PCB &t=IO1_equipment[i];
t.have_IO1=0;
t.need_IO1=0;
t.set_state("ready");
ready_que.push(t);
IO1_equipment.erase(IO1_equipment.begin()+i);
}
else if(num==2){
PCB &t=IO2_equipment[i];
t.have_IO2=0;
t.need_IO2=0;
t.set_state("ready");
ready_que.push(t);
IO2_equipment.erase(IO2_equipment.begin()+i);
}
}
bool ready_to_CPU(){ //就绪队列上处理机(FCFS)
if(CPU.size()==CPU_size || ready_que.empty()) return 0;
PCB &t=ready_que.front();
t.set_state("running");
CPU.push_back(t);
ready_que.pop();
return 1;
}
void block_to_destroy(uint i,uint num){ //有可能出现IO请求被完成之后已经不需要再运行了,直接终止。
if(num==1){ //因为如果按步骤 阻塞队列->就绪队列->CPU->终止 可能会因为所有CPU都在被占用而无法及时执行完此步骤终止该进程。
PCB &t=IO1_equipment[i];
t.End();
t.set_state("destroy");
destroy.push_back(t);
IO1_equipment.erase(IO1_equipment.begin()+i);
}
else if(num==2){
PCB &t=IO2_equipment[i];
t.End();
t.set_state("destroy");
destroy.push_back(t);
IO2_equipment.erase(IO2_equipment.begin()+i);
}
}
Basic_function.h文件
// Created by BingWeiHuang on 2021/4/6.
// 这里是基本函数的声明
// Basic_function.h
#ifndef SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_BASIC_FUNCTION_H
#define SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_BASIC_FUNCTION_H
#include "PCB.h"
using namespace std;
typedef unsigned int uint;
extern uint cur_time;
extern uint CPU_size;
extern uint IO1_equipment_size;
extern uint IO2_equipment_size;
extern double turnover_time_sum;
extern double weighted_turnover_time_sum;
extern vector<PCB> CPU; //处理机
extern vector<PCB> IO1_equipment; //IO1设备
extern vector<PCB> IO2_equipment; //IO2设备
extern queue<PCB> ready_que; //就绪队列
extern queue<PCB> block_IO1_que; //请求IO1设备阻塞队列
extern queue<PCB> block_IO2_que; //请求IO2设备阻塞队列
extern vector<PCB> destroy; //待销毁
bool input_valid(uint need_running_t,uint when,uint time);//检测 ”运行多长时间之后需要IO1设备以及需要多长时间的输入“ 是否合理
PCB createProgress(uint index);//创建进程
void printProgresses();//输出各个进程的情况
bool scan_CPU();//扫描CPU 将该下的进程下CPU
void CPU_runProgresses();//模拟CPU的运行
void ready_wait();//就绪队列每个进程的等待模拟 其实就是waiting_time++
bool scan_IO_equipment(uint num);//扫描IO设备 看看是否有进程使用完毕
void use_IO_equipment();//模拟IO设备的使用 其实就是need_IO1(2)_time--;
void block_wait();//阻塞队列每个进程的等待模拟 其实就是waiting_time++
bool block_que_to_IO(uint num);//给阻塞队列的进程安排IO设备 其实就和就绪队列上CPU类似 只不过这里是没有状态的转换 都是阻塞态
void destroyProgresses();//销毁已经终止的进程
#endif //SIMPLE_THREE_STATE_SIMULATION_OF_THE_PROCESS_BASIC_FUNCTION_H
Basic_function.cpp文件
// 这里是基本函数的实现
// Basic_function.cpp
#include "Basic_function.h"
#include "State_transition.h"
bool input_valid(uint need_running_t,uint when,uint time){ //检测 ”运行多长时间之后需要IO1设备以及需要多长时间的输入“ 是否合理
return (need_running_t>=when)&&(time);
}
PCB createProgress(uint index){ //创建进程
string name,state="ready";
uint need_running_t,arrive_t;
bool IO1,IO2;
printf("\n进程序号: %d\n",index);
printf("请输入进程名称:");
cin>>name;
printf("请输入预计运行时间:");
cin>>need_running_t;
printf("请输入到达时间:");
cin>>arrive_t;
printf("进程是否需要IO1或IO2设备(1表示需要 0表示不需要):");
cin>>IO1>>IO2;
PCB res(index,name,state,need_running_t,arrive_t,IO1,IO2);
uint when1,time1,when2,time2;
if(IO1){
printf("请输入运行多长时间后需要IO1设备 需要多长时间:");
cin>>when1>>time1;
while(!input_valid(need_running_t,when1,time1)){
cout<<endl<<"输入数据不合理 请重新输入:";
cin>>when1>>time1;
}
res.when_need_IO1=when1;res.IO1_time=res.need_IO1_time=time1;
}
if(IO2){
printf("请输入运行多长时间之后需要IO2设备 需要多长时间:");
cin>>when2>>time2;
while(!input_valid(need_running_t,when2,time2) || when1==when2){
cout<<endl<<"输入数据不合理 请重新输入:";
cin>>when2>>time2;
}
res.when_need_IO2=when2;res.IO2_time=res.need_IO2_time=time2;
}
return res;
}
void printProgresses(){ //输出各个进程的情况
printf("\n******************************************************************************************\n");
printf("目前时间: %d\n",cur_time);
printf("\n处理机上有 %d 个进程正在运行:\n",CPU.size());
for(auto progress:CPU) progress.print();
queue<PCB> tmp=ready_que; //拷贝一个副本进行操作 以免影响到原始的进程队列
printf("\n就绪队列中存在 %d 个进程:\n",tmp.size());
while(tmp.size()){
tmp.front().print();
tmp.pop();
}
printf("\nIO1设备上有 %d 个进程正在IO:\n",IO1_equipment.size());
for(auto progress:IO1_equipment) progress.print();
tmp=block_IO1_que;
printf("\nIO1阻塞队列中存在 %d 个进程:\n",tmp.size());
while(tmp.size()){
tmp.front().print();
tmp.pop();
}
printf("\nIO2设备上有 %d 个进程正在IO:\n",IO2_equipment.size());
for(auto progress:IO2_equipment) progress.print();
tmp=block_IO2_que;
printf("\nIO2阻塞队列中存在 %d 个进程:\n",tmp.size());
while(tmp.size()){
tmp.front().print();
tmp.pop();
}
printf("\n待销毁 %d 个进程:\n",destroy.size());
for(auto progress:destroy) progress.print();
cout<<endl;
}
bool scan_CPU(){ //扫描CPU
bool f=0;
for(uint i=0;i<CPU.size();i++){
PCB &t=CPU[i];
if(t.need_IO1&&t.when_need_IO1==t.get_running_time()){ //进程到了该IO1的时刻
CPU_to_block(i,1);
i--;f=1;
}
else if(t.need_IO2&&t.when_need_IO2==t.get_running_time()){ //进程到了该IO2的时刻
CPU_to_block(i,2);
i--;f=1;
}
else if(t.get_running_time()==t.get_need_running_time()){ //进程达到预计运行时间运行该终止了 不能将该条放在最前面if里面 因为会出现预计运行时间运行完后再需要IO的情况
CPU_to_destroy(i);
i--;f=1;
}
}
return f; //是否有进程下CPU了
}
void CPU_runProgresses(){ //模拟CPU运行
for(uint i=0;i<CPU.size();i++) CPU[i].Run(); //就是每个进程running_time++
}
void ready_wait(){ //就绪队列每个进程的等待模拟 其实就是waiting_time++
if(ready_que.empty()) return ;
queue<PCB> tmp=ready_que; //因为queue不提供迭代器遍历 所以借助一个tmp副本进行逐个操作
while(ready_que.size()) ready_que.pop();
while(tmp.size()){
tmp.front().Wait();
ready_que.push(tmp.front());
tmp.pop();
}
}
bool scan_IO_equipment(uint num){
bool f=0;
if(num==1){
for(uint i=0;i<IO1_equipment.size();i++){
PCB &t=IO1_equipment[i];
if(t.need_IO1_time==0){
if(t.get_running_time()==t.get_need_running_time()){ //出现了IO请求被完成之后已经不需要再运行了,直接终止
block_to_destroy(i,1);
}
else
block_to_ready(i,1);
f=1;i--;
}
}
}
else if(num==2){
for(uint i=0;i<IO2_equipment.size();i++){
PCB &t=IO2_equipment[i];
if(t.need_IO2_time==0){
if(t.get_running_time()==t.get_need_running_time()){ //出现了IO请求被完成之后已经不需要再运行了,直接终止
block_to_destroy(i,2);
}
else
block_to_ready(i,2);
f=1;i--;
}
}
}
return f;
}
void use_IO_equipment(){
for(uint i=0;i<IO1_equipment.size();i++){
IO1_equipment[i].need_IO1_time--;
}
for(uint i=0;i<IO2_equipment.size();i++){
IO2_equipment[i].need_IO2_time--;
}
}
void block_wait(){
queue<PCB> tmp=block_IO1_que;//因为queue不提供迭代器遍历 所以借助一个tmp副本进行逐个操作
while(block_IO1_que.size()) block_IO1_que.pop();
while(tmp.size()){ //模拟等待
tmp.front().Wait();
block_IO1_que.push(tmp.front());
tmp.pop();
}
tmp=block_IO2_que;
while(block_IO2_que.size()) block_IO2_que.pop();
while(tmp.size()){ //模拟等待
tmp.front().Wait();
block_IO2_que.push(tmp.front());
tmp.pop();
}
}
bool block_que_to_IO(uint num){
if(num==1){
if(IO1_equipment.size()==IO1_equipment_size || block_IO1_que.empty()) return 0;
PCB &t=block_IO1_que.front();
t.have_IO1=1;
IO1_equipment.push_back(t);
block_IO1_que.pop();
return 1;
}
else if(num==2){
if(IO2_equipment.size()==IO2_equipment_size || block_IO2_que.empty()) return 0;
PCB &t=block_IO2_que.front();
t.have_IO2=1;
IO2_equipment.push_back(t);
block_IO2_que.pop();
return 1;
}
return 0;
}
void destroyProgresses(){ //销毁已经终止的进程
for(auto i:destroy){
turnover_time_sum+=i.turnover_time();
weighted_turnover_time_sum+=i.weighted_turnover_time();
}
destroy.clear();
}
验证:
总结:
这算是实现脑子里面奇奇怪怪的想法?
反正就瞎写,也不知道思路正不正,但从我个人的验证来看程序应该是没什么大毛病(可能只是没有测试到,就算有也不承认 ,你们也可以试试,试到了悄咪咪告诉我就行,哈哈哈)。
可能有人就会问了,为什么不用java写?为什么不用py?
但是我老师曰过:“其实那些个什么java啊、py啊。。。go语言啊什么‘乱七八糟’的语言底层都是C”,所以我选择用C++,嘿嘿嘿。
(好吧,不装了,摊牌了,其实我就只会写一点点C,其他的语言都不会哇呜呜呜呜呜~)
其实代码里面的细节还是做的不到位很多地方要整改,而且还有很多需要完善和补充的地方,比如:
1.进程调度的其他算法(害,我只会FCFS)
2.优先级,当两个处于相同状态进程同时需要争抢最后一份资源(IO设备、CPU)的时候该怎么处理(此时FCFS不奏效,因为“同时”,这就要涉及到优先级了,太麻烦了太难了 暂时不写)
3.高级调度(后备队列进入内存)需要考虑(昨天听操作系统老师讲题目才意识到,从后备队列高级调度到就绪队列也是需要进行写算法限制一下的,毕竟实际上内存大小有限。所以上课直接全程神游于我自己写的代码中,到底怎么样新增高级调度的算法可以实现内存大小限制,怎么样又可以解决进程在内存中不能移动的情况的限制,啊…太复杂了,水瓶有限写不来写不来…)
4.五状态模型
5.写一个能解放纸笔的程序来解那些个我不想不会 写的题??
下次接着完善吧,这次对于我来说已经是一场小型的头脑风暴了。(打码两分钟 debug一小时是真的痛苦,太多了,眼睛都花了,第一次独立写这么多的代码。)