操作系统 进程控制 实验(C语言)
进程控制
基本要求
模拟操作系统内核对进程的控制和管理:包括进程的创建和撤销、进程状态的切换和简单的内存空间管理。
实验提示
1、 定义管理每个进程的数据结构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; }
2、 模拟触发进程状态转换的事件:采用键盘控制方法来模拟触发进程状态切换的事件(例如输入1代表创建新进程、2执行进程时间片到、3阻塞执行进程、4唤醒第一个阻塞进程、5终止执行进程),实现对应的控制程序。
3、 根据当前发生的事件对进程的状态进行切换,并显示出当前系统中的执行队列、就绪队列和阻塞队列。
4、 *(选做)完成可变分区的分配与回收,创建进程的同时申请一块连续的内存空间,在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<stdlib.h> #include<string.h> using namespace std; struct PCB{ char name[8]; struct PCB *next; }; struct PCB *ready,*blocked,*running; struct PCB *p=(struct PCB *)malloc(sizeof(struct PCB)); //插入队列 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; } //出队列 struct PCB *movefirst(struct PCB *head){ struct PCB *tmp=head->next; if(tmp!=NULL) { head->next=tmp->next; tmp->next=NULL; } return tmp; }; //创建进程 void creat() { struct PCB *tmp; char name[10]; cout<<"输入进程名字:"; cin>>name; tmp=(struct PCB*)malloc(sizeof(struct PCB)); strcpy(tmp->name,name); //字符串复制函数 tmp->next=NULL; add(ready,tmp); if(running==NULL) //如果当前没有正在执行的进程就将新创建的进程运行 running=movefirst(ready); } //时间片到 void timeout(){ if(ready->next==NULL) // 容错处理 cout<<"\t\t就绪队列为空!"<<endl; if(running!=NULL) { add(ready,running); running=movefirst(ready); } else running=movefirst(ready); } //阻塞进程 void block(){ if(running!=NULL) { add(blocked,running); running=movefirst(ready); } else cout<<"\t\t没有运行的进程,无法阻塞!"<<endl; } //唤醒进程 void wakeup(){ if (blocked->next == NULL){ printf("阻塞态已为空!!!\n"); } else{ struct PCB *T = (struct PCB*)malloc(sizeof(struct PCB)); T = movefirst(blocked); add(ready,T); if (running == NULL){ running =movefirst(ready); } } } //终止进程 void stop(){ if(running!=NULL) { free(running); running=movefirst(ready); } else cout<<"\t\t没有运行的进程"<<endl; } //展示 void show() { struct PCB *tmp; cout<<endl; cout<<"执行队列:"; if(running!=NULL) cout<<" "<<running->name; cout<<endl; cout<<"就绪队列:"; tmp=ready->next; while(tmp!=NULL){ cout<<" "<<tmp->name; tmp=tmp->next; } cout<<endl; cout<<"阻塞队列:"; tmp=blocked->next; while(tmp!=NULL){ cout<<" "<<tmp->name; tmp=tmp->next; } cout<<endl; cout<<endl; } //菜单 void menu() { cout<<"\t\t--------------------"<<endl; cout<<"\t\t1.创建进程"<<endl; cout<<"\t\t2.时间片到"<<endl; cout<<"\t\t3.阻塞进程"<<endl; cout<<"\t\t4.唤醒进程"<<endl;; cout<<"\t\t5.终止进程"<<endl; cout<<"\t\t6.退出程序"<<endl; cout<<"\t\t--------------------"<<endl; } main() { ready=(struct PCB*)malloc(sizeof(struct PCB)); ready->next=NULL; blocked=(struct PCB*)malloc(sizeof(struct PCB)); blocked->next=NULL; int c; while(1) { menu(); cout<<"输入功能:"; cin>>c; switch(c) { case 1: creat(); break; case 2: timeout(); break; case 3: block(); break; case 4: wakeup(); break; case 5: stop(); break; case 6: exit(0); default: cout<<"没有这个选项,请重新输入"<<endl; } show(); } }
本文来自博客园,作者:王回甘,转载请注明原文链接:https://www.cnblogs.com/WScoconut/p/16383038.html