实验一 多级反馈队列调度算法
一. 主要实现方法和代码介绍
1.编写进程类,其只包含所需的运行时间和进程编号两个属性,还有一个运行方法,此方法就是将所需的运行时间属性减去.传入的运行时间.
2.创建进程函数:创建maxp个进程,(应该不超过10,在此创建九个,即暂时不进行进程队列越界处理),其运行时间符合均值为0,方差为20的高斯分布,并取整取绝对之后所得到的值, (此处是为了全自动创建进程),进程号自己自增. 在创建进程时,使用mutex库将每一个queue 加锁和解锁,以实现互斥访问.
3.运行函数. 主要的算法函数. 首先判断队列非空,即进入运行,一级队列非空时,优先运行第一级队列,一级队列空后,才检差后几级队列. 但是后几级队列每一次执行后,都重新检查一级队列是否非空.具体实现是:if(一级队列非空) { while(一级队列非空){ 运行}} ;而高级别不执行while. 其次,当一次执行没有执行完,则立即放入下一级队列,每次写入都加锁.
二. 程序流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B8AyJRjO-1647856457764)(C:\Users\51330\AppData\Roaming\Typora\typora-user-images\image-20211009101816266.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S14kJ5Lg-1647856457765)(C:\Users\51330\AppData\Roaming\Typora\typora-user-images\image-20211009101923526.png)]
三. 程序代码
#include <iostream>
#include <queue>
//随机数
#include <random>
#include <chrono>
#include <cmath>
#include <thread>
#include <mutex>
#define T 10
#define Qsize 10
using namespace std;
mutex mym1;
mutex mym2;
mutex mym3;
mutex mym4;
int ALLP = 0;
int CPUTIME = 0;
int information = 0;
class Process
{
public:
int RUNTIME;
int PNUM;
void run(int runt);
};
void Process::run(int rt)
{
cout << CPUTIME << ":" << ends;
if (rt >= RUNTIME)
{
RUNTIME = 0;
cout << "进程" << PNUM << "已运行完." << endl;
CPUTIME += rt;
}
else
{
RUNTIME -= rt;
cout << "进程" << PNUM << "已运行" << rt << "时,还需" << RUNTIME << "时即可运行完." << endl;
CPUTIME += rt;
}
}
queue<Process> q1, q2, q3, q4;
void createProcess(int maxp)
{
// 从epoch(1970年1月1日00:00:00 UTC)开始经过的纳秒数,unsigned类型会截断这个值
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
// 第一个参数为高斯分布的平均值,第二个参数为标准差
std::normal_distribution<double> distribution(0.0, 20.0);
// for (int i = 0; i < 10; ++i)
// std::cout << distribution(generator) << std::endl;
for (int i = 1; i <= maxp; i++)
{
Process c1;
c1.RUNTIME = std::abs((int)distribution(generator));
c1.PNUM = ALLP++;
mym1.lock();
q1.push(c1);
mym1.unlock();
cout << "已创建" << ALLP - 1 << "号进程,需要" << c1.RUNTIME << "时来完成." << endl;
}
information++;
}
void running()
{
int performed = 0;
while (true)
{
// if (!q1.empty() || !q2.empty() || !q3.empty() || !q4.empty())
{
if (!q1.empty())
{
while (!q1.empty())
{
Process c1 = q1.front();
mym1.lock(); // lock
q1.pop();
mym1.unlock();
c1.run(T);
if (c1.RUNTIME != 0)
{
if (q2.size() < Qsize)
{
mym2.lock(); //加锁
q2.push(c1);
mym2.unlock();
}
else
{
暂时没管队列已满时的卡死状态
}
}
}
}
else if (!q2.empty())
{
Process c2 = q2.front();
mym2.lock();
q2.pop();
mym2.unlock();
c2.run(2 * T);
if (c2.RUNTIME != 0)
{
if (q3.size() < Qsize)
{
mym3.lock();
q3.push(c2);
mym3.unlock();
}
else
{
暂时没管队列已满时的卡死状态
}
}
if (!performed)
{
createProcess(9);
performed = 1;
}
}
else if (!q3.empty())
{
Process c3 = q3.front();
mym3.lock();
q3.pop();
mym3.unlock();
c3.run(4 * T);
if (c3.RUNTIME != 0)
{
if (q4.size() < Qsize)
{
mym4.lock();
q4.push(c3);
mym4.unlock();
}
else
{
暂时没管队列已满时的卡死状态
}
}
}
else if (!q4.empty())
{
Process c4 = q4.front();
mym4.lock();
q4.pop();
mym4.unlock();
c4.run(8 * T);
if (c4.RUNTIME != 0)
{
if (q4.size() < Qsize)
{
mym4.lock();
q4.push(c4);
mym4.unlock();
}
else
{
暂时没管队列已满时的卡死状态
}
}
}
else
{
cout << CPUTIME << ":当前时刻所有进程已运行完." << endl;
while (!q1.empty() || !q2.empty() || !q3.empty() || !q4.empty())
{
break;
}
if (information == 2)
break;
} // }
}
}
}
int main()
{
// thread t1(createProcess, 9);
createProcess(9);
thread t2(running);
// t1.join();
t2.join();
return 0;
}
四. 运行结果
五.结果分析
观察上方运行结果即可得到:
-
先进行创建进程,创建了九个进程. 而后当一级队列运行完成后,再次创建了九个进程,后面重新从一级队列开始运行. 运行完后,才运行下级队列的1~7号进程.
故可以看出,一级队列最高优先级实现成功.
-
代码缺陷分析:
- 创建进程和运行不能同步进行. 虽然尝试实现创建两个线程,让运行函数和创建进程的函数分开运行,通过对共享变量(共享内存通信)的修改通知不同的进程运行,但总是进入死循环,尝试失败
- 没有按照老师上课讲得PCB的大部分信息来创建进程, 而是偷懒只考虑自己的模拟需求,只有运行时间和进程号两个属性.
. 运行完后,才运行下级队列的1~7号进程.
故可以看出,一级队列最高优先级实现成功.
-
代码缺陷分析:
- 创建进程和运行不能同步进行. 虽然尝试实现创建两个线程,让运行函数和创建进程的函数分开运行,通过对共享变量(共享内存通信)的修改通知不同的进程运行,但总是进入死循环,尝试失败
- 没有按照老师上课讲得PCB的大部分信息来创建进程, 而是偷懒只考虑自己的模拟需求,只有运行时间和进程号两个属性.