进程控制
●基本要求:模拟操作系统内核对进程的控制和管理:包括进程的创建和撤销、进程状态的切换和简单的内存空间管理。
●参考学时:6学时
●实验提示:
- 定义管理每个进程的数据结构PCB:包含进程名称、队列指针、分配的物理内存区域(基址和长度)。每创建一个进程时,需要为其创建PCB并分配空闲内存空间,对PCB进行初始化,并加入就绪队列。(斜体为可选)
可参考如下数据结构(动态形式):
struct PCB{ char name[8]; struct PCB *next; ... }; struct PCB *ready,*blocked,*running; |
创建进程时申请空白PCB:
struct PCB *p=(struct PCB *)malloc(sizeof(struct PCB)); |
并把新建进程的PCB添加到就绪队列末尾:
add(ready,p); |
其中,ready为就绪队列头节点,并在开始处分配了空间;add函数是链表中添加节点函数,代码参考如下:
void add(struct PCB *head, struct PCB *process){ struct PCB *tmp=head; while(tmp->next!=NULL) tmp=tmp->next; tmp->next=process; process->next=NULL; } |
- 模拟触发进程状态转换的事件:采用键盘控制方法来模拟触发进程状态切换的事件(例如输入1代表创建新进程、2执行进程时间片到、3阻塞执行进程、4唤醒第一个阻塞进程、5终止执行进程),实现对应的控制程序。
- 根据当前发生的事件对进程的状态进行切换,并显示出当前系统中的执行队列、就绪队列和阻塞队列。
- *(选做)完成可变分区的分配与回收,创建进程的同时申请一块连续的内存空间,在PCB中设置好基址和长度,结束进程时回收分配的内存空间。分配可采用首次适应、最佳适应或最差适应算法,碎片大小为2Kb,最后回收所有进程的空间,对空间分区的合并。可以查看进程所占的空间和系统空闲空间。
- 可以用一个链表(如图1-1所示)来维护已分配的和空闲的内存段,其中一个段或者包含一个进程,或者是两个进程之间的空闲段。 在图1-1中,链表的每一项包含四个值域。第一个值域表示内存段是空闲或占用(例如,空闲段用H表示,进程占用的段用P表示);第二个值域表示内存段的起始位置,第三个值域表示内存段的长度;第四个值域为指向链表下一项的指针。该链表按照内存段的起始地址进行从小到大排序。这样排序的好处是方便内存空间的回收。一个要终止的进程一般会有两个邻居(除了在内存顶端和内存底端的进程)。邻居可能是进程也可能是空闲段。根据两个邻居的不同类型,可以分为四种回收情况(如图1-2所示)。在图1-2(a)中,对链表的更新只需要将P置为H;在图1-2(b)和(c)中,需要将P置为H,并将该项与另外一个相邻的空闲段的项合并为一项;在图1-2(d)中,需要将该项和两个邻居合并为一项。考虑到合并空闲段需要查看邻居,因此用双向链表会比单向链表更加方便。
图 1-1. (a) 内存空间的示例,有5个进程和3个空闲段,阴影部分表示空闲段。
(b) 管理内存空间的链表
图 1-2. 对终止的进程X的四种内存回收情况(阴影代表空闲区)
代码
#include<iostream>
#include<queue>
#include<string>
#include<sstream>
#include<list>
using namespace std;
//PCB
class PCB {
public:
string name;
int base;//基址
int length;//长度
};
//内存块
class Memory_Block {
public:
char state;//状态,H表示空闲,P表示占用
int base;//基址
int length;//长度
};
//状态队列
queue<PCB> ready;
queue<PCB> run;
queue<PCB> blockage;//阻塞
//内存管理
list<Memory_Block> memory;
void help();
bool creat(string name, int length);
void close();
void timeslice_end();
void clogging();
void awaken();
void view(int flag);
int main() {
cout<< "This is a programe to show how the processes work!\nIt is made by Gin.\nYou can see the Help by commend 'H'!\n\nPlease input two number instead of the begin and the size!\n";
int begin, size;
cin >> begin >> size;
getchar();
memory.push_back({ 'H',begin,size });
cout << "You have successfully create a new memory!\n";
string directives="";//指令
while (directives != "Q" || directives != "q") {
cout << ">";
//cin.ignore(100, '\n');
cin >> directives;
getchar();
if (directives == "H" || directives == "h") {
help();
}
else if (directives[0] == 'c' || directives[0] == 'C') {
string name;
int length;
cin >> name >> length;
creat(name, length);
getchar();
}
else if (directives == "Q" || directives == "q") {
return 0;
}
else if (directives == "E" || directives == "e") {
close();
}
else if (directives == "T" || directives == "t") {
timeslice_end();
}
else if (directives == "B" || directives == "b") {
clogging();
}
else if (directives == "W" || directives == "w") {
awaken();
}
else if (directives == "s1" || directives == "s2" || directives == "S1" || directives == "S2") {
if (directives == "s1" || directives == "S1") {
view(1);
}
else {
view(2);
}
}
else {
cout << "Wrong commend!\n";
}
}
}
void help() {
cout << "命令使用:\n1.创建:C / c + 空格 + 进程名字 + 进程大小.\n2.调度 : (要求自动).\n3.终止 : E / e 结束正在运行的进程.\n4.时间片到 : T / t : 将运行的进程装入就绪队列尾部, 将下一个自动调度过来.\n5.阻塞 : B / b 将正在执行的程序阻塞, 即插入阻塞队列尾部.\n6.唤醒 : W / w 将阻塞队列中的一个进程调度到就绪队列上, 即阻塞队列头到就绪队列尾.\n7.查看 : 随时查看队列的情况 : S / s(Show) 1 / 2.(s1 查看的是三个进程队列的情况,s2查看的是剩余内存的情况)\n8.退出:Q / q.\n";
}
bool creat(string name, int length) {
queue<PCB> temp = ready;
while (!temp.empty()) {
if (temp.front().name == name) {
cout << "The process s has exist,and you can see where it is by commend '" << name << "'\n";
return false;
}
temp.pop();
}
temp = run;
while (!temp.empty()) {
if (temp.front().name == name) {
cout << "The process s has exist,and you can see where it is by commend '" << name << "'\n";
return false;
}
temp.pop();
}
temp = blockage;
while (!temp.empty()) {
if (temp.front().name == name) {
cout << "The process s has exist,and you can see where it is by commend '" << name << "'\n";
return false;
}
temp.pop();
}
for (auto i = memory.begin(); i != memory.end(); i++) {
if (i->state == 'H' && i->length >= length) {
PCB pcb;
if (length + 2 >= i->length) {
i->state = 'P';
pcb.name = name;
pcb.base = i->base;
pcb.length = i->length;
}
else {
i->state = 'P';
Memory_Block mb;
mb.state = 'H';
mb.base = i->base+length;
mb.length = i->length-length;
i->length = length;
if (next(i) != memory.end()) {
memory.emplace(next(i), mb);
}
else {
memory.push_back(mb);
}
pcb.name = name;
pcb.base = i->base;
pcb.length = length;
}
cout << "You successfully create a process named " << name << ".\n";
if (run.size() == 0) {
run.push(pcb);
}
else {
ready.push(pcb);
}
return true;
}
}
cout << "There is no memory for this process,create Fail!\n";
return false;
}
void close() {
string name;
if (run.size() == 0) {
cout << "There is no running process!\n";
return;
}
else {
name = run.front().name;
PCB pcb=run.front();
run.pop();
if (ready.size() != 0) {
PCB pcb2 = ready.front();
ready.pop();
run.push(pcb2);
}
for (auto it = memory.begin(); it != memory.end();it++) {
if (it->state=='P'&&it->base==pcb.base&&it->length==pcb.length) {
it->state = 'H';
if (it != memory.begin()) {
if (prev(it)->state == 'H') {
prev(it)->length += it->length;
auto temp = prev(it);
memory.erase(it);
it = temp;
}
}
if (next(it) != memory.end()) {
if (next(it)->state == 'H') {
it->length += next(it)->length;
memory.erase(next(it));
}
}
cout << "Process named " << name << " has been killed.\n";
return;
}
}
}
}
void timeslice_end() {
if (ready.size() == 0) {
cout << "There is no running process!\n";
}
else {
PCB pcb = run.front();
run.pop();
PCB pcb2 = ready.front();
ready.pop();
ready.push(pcb);
run.push(pcb2);
cout << "Process named " << pcb.name << "'s time is over.\n";
}
}
void clogging() {
if (run.size() == 0) {
cout << "There is no running process!\n";
}
else {
PCB pcb = run.front();
run.pop();
blockage.push(pcb);
cout << "Process named " << pcb.name << " has been blocked.\n";
}
if (ready.size() != 0) {
PCB pcb2 = ready.front();
ready.pop();
run.push(pcb2);
}
}
void awaken() {
if (blockage.size() == 0) {
cout << "There is no blocking process!\n";
}
else {
PCB pcb = blockage.front();
blockage.pop();
if (run.size() == 0) {
run.push(pcb);
}
else {
ready.push(pcb);
}
cout << "Process named " << pcb.name << " has been waked up.\n";
}
}
void view(int flag) {
if (flag == 1) {//s1
cout << "The information will be showed in name(begin,size)\n";
cout << "Ready Processes :";
queue<PCB> temp = ready;
while(!temp.empty()){
cout << temp.front().name << "(" << to_string(temp.front().base) << "," << to_string(temp.front().length) << ") ";
temp.pop();
}
cout << endl;
temp = run;
cout << "Executing Processes :";
while (!temp.empty()) {
cout << temp.front().name << "(" << to_string(temp.front().base) << "," << to_string(temp.front().length) << ") ";
temp.pop();
}
cout << endl;
temp = blockage;
cout << "Blocking Processes :";
while (!temp.empty()) {
cout << temp.front().name << "(" << to_string(temp.front().base) << "," << to_string(temp.front().length) << ") ";
temp.pop();
}
cout << endl;
}
else {//s2
cout << "The left memory:\n";
for (auto i : memory) {
if (i.state == 'H') {
cout << "Start:" << to_string(i.base) << "," << "Size:" << to_string(i.length) << "\n";
}
}
}
}