实验一、进程创建、调度与撤消
实验一、进程创建、调度与撤消
一、目的
通过进程的创建和调度的设计来达到如下目的:
- 加深对进程概念的理解,明确进程和程序的区别;
- 进一步认识并发执行的概念,区别顺序执行和并发执行;
- 深入了解系统如何组织进程,创建进程;
- 进一步认识如何实现处理机调度。
二、内容
????????在WINDOWS环境下模拟实验:
- 编写一程序,来模拟进程的创建和撤消,要求通过终端键盘输入几个作业的名称、大小、优先级等。系统为它创建进程,并把进程控制块PCB(进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、程序大小、已用CPU时间、进程状态等等)的内容送到终端显示器上输出。
- 同时模拟内存空间为作业分配内存空间,并把结果用图形形象地表示出来,同样通过终端输出。
- 从下面四个调度算法中,选择一个调度算法来实现进程调度:
????????a、先来先服务调度算法;
????????b、短进程优先调度算法;
????????c、优先数调度算法;
????????d、时间片轮法调度算法;
三、详细设计
该模拟系统主要,主要使用结构体存储PCB的基本信息和就绪队列链队LinkQueue,写了6个关键的函数,具体实现如下:
?---PCB结构体、就绪队列LinkQueue(采用链队的存储方式)如下:
(1)//控制块PCB的信息
struct PCB
{
? ? char name[10];
? ? int id;
? ? int atime; //进程到达时间
? ? int stime; //服务时间,运行时间
? ? int ftime; //进程完成时间
? ? int size;
? ? int prior; //进程优先级
};//使用链队进行存储
(2)//就绪队列
typedef struct Tnode *T; // struct Tnode的别名为*T
struct Tnode
{
? ? int data; //?什么数据/存储当前创建的进程数
? ? T next; ? //指向就绪队列的下一位置
};(3)//消息缓冲队列
struct Linkqueue
{
? ? T front, rear; //头指针和尾指针分别指向就绪队列的头部和尾部
};
?
?
---主要函数如下:
(1)InitQueue():初始化就绪队列,主要将指向就绪队列的头指针和尾指针初始化,方便后面进程的创建。
(2)EnterQueue() ——将PCB插入到链队L中。
(3)create_PCB()——创建进程,首先申请一个空的PCB,然后为该进程分配空间资源,然后初始化PCB,填入进程参数,最后通过调用EnterQueue()函数将该PCB插入到就绪链队L中。若内存不够则申请失败。
(4)sort_FCFS() ——采用先来先服务算法对就绪队列进行排序,遍历pcb,如果当前进程比后一个进程的到达时间长,就交换。
(5)Finish_Time()——计算经过sort_FCFS排序后的每个PCB进程的完成时间。
(6)kill_PCB( )——终止进程,将指定的就绪进程移出就绪队列中,并清除PCB中的信息。
(7)display_PCB() —— 显示已经在就绪队列中的进程。
四、源代码
详细源代码如下:
#include <stdio.h>
#include <stdlib.h>
// #define MAX_size 200 //表示最大内存
#define MAX_num 20 //单次最大进程数
//控制块PCB的信息
struct PCB
{
char name[10];
int id;
int atime; //进程到达时间
int stime; //服务时间,运行时间
int ftime; //进程完成时间
int size;
int prior; //进程优先级
};
//使用链队进行存储
//就绪队列
typedef struct Tnode *T; // struct Tnode的别名为*T
struct Tnode
{
int data; //?什么数据/存储当前创建的进程数
T next; //指向就绪队列的下一位置
};
//消息缓冲队列
struct Linkqueue
{
T front, rear; //头指针和尾指针分别指向就绪队列的头部和尾部
};
//定义全局变量
Linkqueue L; //消息缓冲队列结构体
PCB pcb[MAX_num]; //结构体PCB数组,MAX_num最大进程数
int numpcb = 0; /当前已经创建的进程数目
int ram_size; //内存大小
//就绪队列的初始化
void InitQueue()
{
L.rear = L.front = (T)malloc(sizeof(T));
if (!L.front)
exit(-2);
L.front->next = NULL;
}
//判断链队是否为空
bool EmptyQueue()
{
if (L.front == L.rear)
return true;
else
return false;
}
//(2)将PCB插入就绪队列中
void EnterQueue(Linkqueue &L, int x)
{
T s = (T)malloc(sizeof(T)); //创建一个新结点s
s->data = x; //传入新结点s的数据域x值,此时x的值就是结构体数组的下标
s->next = NULL; //设置新结点s的指针域为空
L.rear->next = s; //将新结点s插入至当前链队末尾
L.rear = s; //队尾指针指向新结点s
}
//(3)先来先服务,即 先到达,先服务 进行排序
void sort_FCFS(PCB *q, int num)
{
for (int i = 0; i < num - 1; i++)
{
struct PCB temp; //临时变量,用于交换的中间量
for (int j = i + 1; j < num; j++) //按先到达的排序
{
if (q[i].atime > q[j].atime)
//如果前面的PCB比后面的更晚到达,就往后移
{
temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
}
}
//(3)优先数调度算法排序(1为优先级最高)
void sort_Priority(PCB *q, int num)
{
for (int i = 0; i < num - 1; i++)
{
struct PCB temp; //临时变量,用于交换的中间量
for (int j = i + 1; j < num; j++) //按先到达的排序
{
if (q[i].prior > q[j].prior)
//如果前面的PCB比后面的更晚到达,就往后移
{
temp = q[i];
q[i] = q[j];
q[j] = temp;
}
if (q[i].prior == q[j].prior)
{
if (q[i].atime > q[j].atime)
{
temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
}
}
}
//(4)计算PCB的完成时间
void finish_Time(PCB *pcb, int numpcb)
{
//先使用先来先服务进行排序
// sort_FCFS(pcb, numpcb);
//优先级调度算法
sort_Priority(pcb, numpcb);
for (int i = 0; i <= numpcb; i++)
{
//计算第一个进程的完成时间:达到时间+服务时间
if (i == 0)
pcb[0].ftime = pcb[0].atime + pcb[0].stime;
else
{
if (pcb[i].atime > pcb[i - 1].ftime) //当前的到达时间比上一个的完成时间大的话,直接
pcb[i].ftime = pcb[i].atime + pcb[i].stime;
else
{
pcb[i].ftime = pcb[i - 1].ftime + pcb[i].stime;
// printf("%d", pcb[i].ftime);
}
}
// ram_size=ram_size+pcb[i].size;
}
}
//(1)创建进程:申请PCB
void create_PCB()
{
int num; //要创建的进程数目
printf("\n--请输入要创建的进程数目:");
scanf("%d", &num);
while (num > MAX_num)
{
printf("*提示:进程数太大了,请重新输入!");
scanf("%d", &num);
};
// 1、输入数据
for (int i = 0; i < num; i++)
{
printf("*请输入进程id:");
scanf("%d", &pcb[numpcb].id);
printf("*请输入进程名:");
scanf("%s", &pcb[numpcb].name);
printf("请输入进程的优先级:");
scanf("%d", &pcb[numpcb].prior);
printf("*请输入进程到达时间:");
scanf("%d", &pcb[numpcb].atime);
printf("*请输入进程服务时间:");
scanf("%d", &pcb[numpcb].stime);
printf("*请输入进程大小:");
scanf("%d", &pcb[numpcb].size);
//判断一下内存还够不够
if (pcb[numpcb].size > ram_size)
{
printf("*提示:内存不足,创建失败!\n");
//结束创建
break;
}
else
{
//将PCB插入到就绪队列中
EnterQueue(L, numpcb);
//提示用户
printf("-----%d\n", pcb[numpcb].size);
ram_size = ram_size - pcb[numpcb].size; //创建成功后,为该进程分配了空间,计算剩下的内存空间
printf("剩下内存%d\n", ram_size);
printf("*提示:恭喜%s进程创建成功!\n", pcb[numpcb].name);
numpcb++; //创建成功后,进程数加一
printf("_____________________________");
}
printf("\n");
}
printf("\n---共成功创建了%d个进程", numpcb);
printf("\n---还剩下%d的内存空间!", ram_size);
}
//(6)终止进程,删除进程
void kill_PCB()
{
int id;
T p;
p = L.front; //指向链队的第一个结点
if (L.front == L.rear)
printf("*提示:当前无进程!\n\n");
else
{
printf("请输入要终止的进程id:");
scanf("%d", &id);
while (pcb[p->next->data].id != id)
{
if (p->next == NULL) //到最后没有找到改进程
printf("*提示:进程不存在!\n\n");
p = p->next; //往后移动
}
//找到了id
if (pcb[p->next->data].id == id)
{
//归还内存
ram_size = ram_size + pcb[p->next->data].size;
numpcb--; //总的进程数-1
p->next = p->next->next; //删除该结点p->next
/*当L.front->next==NULL时,说明当前杀死的进程是系统中最后一个进程,此时首位指针指向同一个位置*/
if (L.front->next == NULL)
L.front = L.rear;
/*当p->next==NULL时,说明当前杀死的进程是队尾进程,此时尾指针指向p*/
if (p->next == NULL)
L.rear = p;
while (p->next != NULL)
{
p->next->data--;
pcb[p->next->data] = pcb[p->next->data + 1];
p = p->next;
}
}
printf("*提示:成功杀死进程!\n");
printf("--当前内存剩余:%d!\n", ram_size);
printf("--当前进程数为:%d\n", numpcb);
}
}
void print(PCB *pcb, int numpcb)
{
sort_FCFS(pcb, numpcb);
for (int i = 0; i < numpcb; i++)
{
printf("-----第%d个:\n", i + 1);
printf("进程ID:%d\n 进程名: %s\n 到达时间: %d\n 服务时间: %d\n 完成时间:%d\n", pcb[i].id, pcb[i].name, pcb[i].atime, pcb[i].stime, pcb[i].ftime);
}
}
//(5)显示已经就绪的进程
void display_PCB()
{
printf("\n当前numpcb:%d\n", numpcb);
sort_FCFS(pcb, numpcb);
// print(pcb, numpcb);
// printf("计算时间\n");
finish_Time(pcb, numpcb); //计算完成时间
if (L.front == L.rear)
printf("*提示:当前无进程!");
else
{
T p;
p = L.front->next;
printf("-----就绪进程如下:------\n");
printf("进程ID 进程名 优先级 到达时间 服务时间 完成时间 内存大小\n");
while (p != NULL)
{
printf("%5d\t", pcb[p->data].id);
printf("%4s\t", pcb[p->data].name);
printf("%4d\t", pcb[p->data].prior);
printf("%5d\t", pcb[p->data].atime);
printf("%5d\t", pcb[p->data].stime);
printf("%5d\t", pcb[p->data].ftime);
printf("%5d\t", pcb[p->data].size);
p = p->next;
printf("\n");
}
}
}
//菜单
void menu()
{
int n;
while (1)
{
printf("\n*************进程演示系统*************\n");
printf(" 1.创建进程\n");
printf(" 2.查看进程\n");
printf(" 3.杀死进程\n");
printf(" 4.退出程序\n");
printf("***************************************\n\n");
printf("请输入你的选择(1-4):");
scanf("%d", &n);
switch (n)
{
case 1:
create_PCB();
break;
case 2:
display_PCB();
break;
case 3:
kill_PCB();
break;
case 4:
//退出
break;
default:
printf("没有这个选项!");
break;
}
}
}
int main()
{
printf("\n请输入可用的内存大小:");
scanf("%d", &ram_size);
InitQueue(); //初始化就绪队列
menu();
return 0;
}
?
五、运行效果图
(1)界面初始图
?
(2)创建进程:
?
(3)显示已经在就绪队列中的进程(按照先来先服务进行排序输出):
?
(4)终止某进程
?
六、结果分析
????????此次实验采用c语言模拟进程的创建与撤销,一方面,回忆和复习了原先学习过的链队的创建、插入、遍历等知识点,另一方面,通过写代码更加清楚的理解了PCB进程的创建的基本过程:(1)申请空白PCB;(2)为新进程分配资源;(3)初始化PCB;(4)将新进程插入到就绪队列中。
????????本次实验还采用了先来先服务算法对PCB进程排序之后,再计算出每个PCB进程的完成时间,加深了对先来先服务进程的理解。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!