一、先来先服务
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <new>
#include <string>
#include <cstdio>
using namespace std;
unsigned int sysTime = 0; // 模拟系统的时钟,每运行一次就加1
enum Status {Ready, Complete}; // 就绪态Ready,完成态Complete
class PCB
{
public: // 权限待改进
string name;
Status condition; // 进程当前的状态
unsigned int arriveTime; // 到达时间
unsigned int serveTime; // 服务时间,每执行一次减1,是变化的
unsigned int serveTimeConst; // serveTime运行一次减1,因为最后要算带权周转时间,故用serveTimeConst来保存初始的serveTime
unsigned int startTime; // 开始执行时间
unsigned int endTime; // 完成时间
unsigned int T; // 周转时间turnaroundTime
double W; // 带权周转时间weightedTurnaroundTime
PCB *next;
// 构造函数
PCB(string _name = "", unsigned int _arriveTime = 0, unsigned int _serveTime = 0)
:name(_name),
condition(Ready),
arriveTime(_arriveTime),
serveTime(_serveTime),
serveTimeConst(_serveTime),
startTime(0),
endTime(0),
T(0),
W(0),
next(NULL){}
};
class ReadyQueue
{
public:
PCB *head; // 头指针指向头结点
PCB *tail; // 指向尾结点
// 构造函数
ReadyQueue()
{
head = new(nothrow) PCB(); // 带头结点的链队列
if (NULL == head)
{
cout << "StackOverflow!" << endl;
exit(-1);
}
tail = head; // 设尾指针,初始化为头指针
}
// 输入所有进程
void Input()
{
cout << "请输入各进程名、到达时间及估计服务时间:" << endl;
string name;
unsigned int arrT;
unsigned int serT;
while (cin >> name >> arrT >> serT)
{
EnQueue(name, arrT, serT); // 在就绪队列Q中插入刚来的进程
}
}
// PCB入队,用进程的到达时间和服务时间来初始化
void EnQueue(string _name, unsigned int _arriveTime, unsigned int _serveTime)
{
PCB *p = new(nothrow) PCB(_name, _arriveTime, _serveTime);
if (NULL == p)
{
cout << "StackOverflow!" << endl;
exit(-1);
}
tail->next = p;
tail = tail->next;
}
// 判空
bool IsEmpty()
{
return head == tail;
}
// 执行队首进程
void Run()
{
if (IsEmpty())
{
cout << "队列为空,不能执行!" << endl;
exit(-1);
}
cout << "就绪队列:"; // 不空则先输出所有就绪进程
for (PCB *q = head->next; q != NULL; q = q->next)
{
cout << q->name;
if (q != this->tail)
{
cout << "->";
}
}
PCB *p = head->next; // 取出将要执行的进程
while (sysTime < p->arriveTime) // 若此时进程“还未到达”,则等待(这个最好在入队时判断,但入队和出队应并发执行,待改进)
{
++sysTime;
}
p->startTime = sysTime;
cout << "\n进程" << p->name << "开始运行,估计服务时间为" << p->serveTime << ",此时系统时间为:" << sysTime << endl;
cout << "已运行时间\t剩余运行时间" << endl;
while (p->serveTime != 0) // 执行
{
++sysTime;
--(p->serveTime); // 模拟服务时间-1操作
cout << sysTime - p->startTime << "\t\t"
<< p->serveTime << endl;
}
// 退出执行时服务时间为0,而serveTimeConst保存了初始的服务时间,以便算带权周转时间
cout << "进程" << p->name << "执行完毕!" << endl << endl;
p->condition = Complete;
p->endTime = sysTime;
p->T = p->endTime - p->arriveTime;
p->W = (double)(p->T) / p->serveTimeConst; // 注意类型转换
}
// 删除队首进程,返回该进程的地址
PCB* DeQueue()
{
if (IsEmpty()) // 判空
{
cout << "队空,不得删除!" << endl;
exit(-1);
//return NULL;
}
PCB *p = head->next;
head->next = p->next;
if (tail == p) // 最后一个进程出队时要特别注意
{
tail = head;
}
return p;
//不释放结点,因为最后要输出所有结点的信息
}
// 析构函数
~ReadyQueue() // 后面的结点由StorePCB释放
{
delete head;
head = NULL;
}
};
class StorePCB
{
public:
PCB *front;
PCB *rear;
// 构造函数
StorePCB()
{
front = new(nothrow) PCB(); // 带头结点的链队列
if (NULL == front)
{
cout << "StackOverflow!" << endl;
exit (-1);
}
rear = front; // 设尾指针,初始化为头指针
}
// 输出所有进程信息
void Output()
{
cout << "各进程信息:\n进程名\t周转时间\t带权周转时间" << endl;
for (PCB *p = front->next; p != NULL; p = p->next)
{
cout << p->name << "\t"
<< p->T << "\t\t"
<< p->W << endl;
}
}
// 把p指向的PCB插入S
void EnQueue(PCB *p)
{
if (p == NULL)
{
cout << "不能向存储队列中插入空!" << endl;
exit (-1);
}
p->next = NULL; // 重要,以便最后释放
rear->next = p;
rear = rear->next;
}
// 析构函数
~StorePCB()
{
PCB *p = NULL;
PCB *q = NULL;
for (p = front; p != NULL; p = q)
{
q = p->next;
delete p;
p = NULL;
}
front = NULL;
rear = NULL;
}
};
int main(int argc, char **argv)
{
//freopen("cin.txt", "r", stdin);
//freopen("cout.txt", "w", stdout);
ReadyQueue Q; // 就绪队列Q
StorePCB S; // S用于存储执行完毕的进程(修改指针即可)
unsigned int count = 1;
// 输入进程
Q.Input();
// 执行进程
while (!Q.IsEmpty()) // 只要就绪队列不为空就一直执行
{
cout << "*********************************** Case " << count++ << " ***********************************" << endl;
Q.Run(); // 执行就绪队首进程
PCB *tmp = Q.DeQueue(); // 得到刚执行完毕的进程的地址
S.EnQueue(tmp); // 将执行完毕的进程存储在S中
}
cout << "***************************** 进程全部执行完毕! *****************************" << endl << endl;
// 输出进程的执行信息(周转时间和带权周转时间)
S.Output();
return 0;
}
二、抢占式动态优先权
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <new>
#include <queue>
#include <string>
#include <cstdio>
using namespace std;
unsigned int sysTime = 0; // 模拟系统的时钟,每运行一次就加1
enum Status {Ready, Complete}; // 就绪态Ready,完成态Complete
class PCB
{
public: // 权限待改进
unsigned int priorityNum; // 优先数(优先数越大,优先权越低,0表示最高优先权)
string name; // 进程名
Status condition; // 当前的状态
unsigned int arriveTime; // 到达时间
unsigned int serveTime; // 服务时间(每执行一次减1,是变化的)
unsigned int serveTimeConst; // serveTime运行一次减1,因为最后要算带权周转时间,故用serveTimeConst来保存初始的serveTime
unsigned int startTime; // 开始执行时间
unsigned int endTime; // 完成时间
unsigned int T; // 周转时间turnaroundTime
double W; // 带权周转时间weightedTurnaroundTime
PCB *next; // 指向下个PCB
// 构造函数
PCB(string _name = "",
unsigned int _arriveTime = 0,
unsigned int _serveTime = 0,
unsigned int _priorityNum = 0
)
:name(_name),
condition(Ready),
arriveTime(_arriveTime),
serveTime(_serveTime),
serveTimeConst(_serveTime),
startTime(0),
endTime(0),
T(0),
W(0),
next(NULL),
priorityNum(_priorityNum){}
// 比较优先级,优先数
bool operator<(const PCB &obj) const
{
return this->priorityNum > obj.priorityNum; // 规定优先级与优先数相反
}
};
// 执行队首进程一次
void Run(priority_queue<PCB> &Q)
{
if (Q.empty())
{
cout << "队列为空,不能执行!" << endl;
exit(-1);
}
cout << "就绪队列:";
priority_queue<PCB> myQ(Q); // 要输出优先队列,只能每次都输出队首,故创建一个副本
while (!myQ.empty())
{
cout << myQ.top().name;
myQ.pop();
if (!myQ.empty())
{
cout << " -> ";
}
}
cout << endl;
PCB head(Q.top()); // 优先队列不能对其队首直接修改?
Q.pop();
//head.startTime = sysTime; // 开始执行时间无意义?
sysTime++;
head.priorityNum++;
head.serveTime--;
if (head.serveTime == 0) // 运行完毕
{
cout << "进程" << head.name << "执行完毕" << endl;
head.condition = Complete;
head.endTime = sysTime;
head.T = head.endTime - head.arriveTime;
head.W = (double)(head.T) / head.serveTimeConst;
}
else
{
Q.push(head);
}
}
int main(int argc, char **argv)
{
freopen("cin.txt", "r", stdin);
priority_queue<PCB> Q; // ReadyQueue
string name;
unsigned int arrT;
unsigned int serT;
unsigned int priorityNum;
// 输入进程
cout << "请输入各进程名、到达时间及估计服务时间:" << endl;
while (cin >> name >> arrT >> serT >> priorityNum)
{
Q.push(PCB(name, arrT, serT, priorityNum)); // 在就绪队列Q中插入刚来的进程
}
cout << endl;
while (!Q.empty())
{
Run(Q); // 运行一次
}
return 0;
}