操作系统:进程五状态模型模拟用C语言链队列方法实现

** 可以直接前往8整合看所有代码 **

1.节点的PCB信息

typedef struct PCB {
	QElemType Pid;     /*进程的ID*/
	QElemType Priority;/*进程的优先级,采用优先级的话建议一开始就设置好进程并将他们排序*/
	//(这里没有用到优先级;设置优先级的话建议一开始将进程加入到就绪态队列的时候进行排序)
	QElemType Name;   /*进程的名称*/
	QElemType State;  /*进程的状态 1为新建态 2为就绪态 3为运行态 4为阻塞态 5为退出态*/
	QElemType Time;   /*进程需要运行的时间*/
	//int resoure[1]; /*两种独占的资源;这里没有设置进程所需的独占资源*/
};

2.链队列的信息

//链队列的节点
typedef struct QNode {
	struct PCB pcb;    //节点所具有的信息
	struct QNode* next;//指向下一个节点的指针
}QNode, * Queueptr;

//链队列的结构
typedef struct {
	Queueptr front;   //队列的头指针
	Queueptr rear;    //队列的尾指针
}LinkQueue;

3.基本一些配置信息+队列的初始化方法

#include <stdio.h>
#include<stdlib.h>
#define error 0
#define ok 1

//全局变量
int timeSlice = 3;    /*自定义时间片的长度*/
int number = 0;       /*进程的数目*/

typedef int QElemType;
typedef int Status;

LinkQueue newbuiltQ;  /*新建态进程队列*/
LinkQueue readyQ;     /*就绪态进程队列*/
LinkQueue runQ;       /*运行(执行)态进程队列*/
LinkQueue clogQ;      /*阻塞态进程队列*/

Status InitQueue(LinkQueue* Q)
{
	Q->front = Q->rear = (Queueptr)malloc(sizeof(QNode));
	if (!Q->front) return error; //申请空间失败
	Q->front->next = NULL;       //队头指向空
	return ok;
}

4.模块一:创建一个新进程(建立新建态队列的方法),在队尾插入元素

Status EnQueueCreateThread(LinkQueue* Q)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	/*将PCB内的值赋值给新节点*/
	printf("请输入进程的ID号\n");
	scanf("%d", &s->pcb.Pid);
	printf("请输出进程的优先级\n");
	scanf("%d", &s->pcb.Priority);
	printf("请输入进程的名称\n");
	scanf("%d", &s->pcb.Name);
	s->pcb.State = 1;      /*设置新建的进程为新建态*/
	printf("请输入进程需要运行的时间\n");
	scanf("%d", &s->pcb.Time);

	s->next = NULL;       /*新节点指向NULL*/
	Q->rear->next = s;    /*队尾指针的下一个元素指向新节点*/
	Q->rear = s;          /*队尾指针指向新节点*/

	return ok;
}

5.模块2:先遍历newbuild(新建态)的队列QueueTravel()的方法,将新建态队列中每一个节点的信息复制到就绪队列中+创建就绪态队列在队尾插入元素(每插入一个则将该节点从链队列中取出送入运行态队列)+创建阻塞态队列

Status EnQueue(LinkQueue* Q,QElemType e,QElemType e1, QElemType e2, QElemType e3)//创建就绪态队列在队尾插入元素
{
	
		Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
		if (!s)//分配失败
			exit(0);
		s->pcb.Pid = e;
		s->pcb.Priority = e1;
		s->pcb.Name = e2;
		s->pcb.Time = e3;
		s->pcb.State = 2;

		s->next = NULL;    			/*新节点指向NULL*/
		Q->rear->next = s;   		/*队尾指针的下一个元素指向新节点*/
		Q->rear = s;        		/*队尾指针指向新节点(新节点成为队尾指针指向的节点)*/
		printf("就绪态: %d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);

			//取就绪态头结点给运行态,并且将就绪态队列清空(用的是清空链队列的方法)
			Queueptr p, q;         /*p用来遍历队列的节点,q用来指向被删除的节点*/
			Q->rear = Q->front;    /*队尾指针指向队头指针*/
			p = Q->front->next;    /*p指向队头指针的下一个节点*/
			Q->front->next = NULL; /*队头指针的下一个节点指向NULL(表示删除之后的所有元素)*/

			//当队列中还有元素,释放头结点之后的所有节点
			while (p) {
				//将p指向的节点信息以此送入运行态队列
				GetHeadAndCreateRunThread(&runQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
				q = p;		 	  /*q节点指向被删除节点*/
				p = p->next;      /*p指向队列的下一个节点*/
				free(q);          /*释放节点q*/
		}

}

//遍历newbuild(新建态)的队列,将新建态队列中每一个节点的信息复制到就绪队列中
Status QueueTravel(LinkQueue* Q) /*这里的参数有main方法里传入*/
{	
	Queueptr p;         		/*用于遍历队列中的节点*/
	p = Q->front->next; 		/*p指向新建态队列的头结点*/
	
	while (p) { 
		/*将新建态队列的PCB内的信息复制到就绪队列相应的节点上*/
		EnQueue(&readyQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		p = p->next;			/*p移动到队列的下一个位置*/
	}

	//当新建态队列的PCB内的信息复制到就绪队列相应的节点上完成之后将新建态队列清空
	Queueptr n, m;        /*n用来遍历队列的节点,m用于指向被删除的节点*/
	Q->rear = Q->front;   /*队尾指针指向队头指针*/
	n = Q->front->next;	  /*n指向队头指针的下一个节点*/
	Q->front->next = NULL;/*队头指针的下一个节点指向NULL(表示删除之后的所有元素)*/
	//当队列中还有元素,释放头结点之后的所有结点
	while (n) {
		m = n;            /*m结点指向被删除节点*/
		n = n->next;	  /*n指向队列的下一个节点*/
		free(m);	  	  /*释放m节点*/
	}
	if(Q->front == Q->rear)
	{
		printf("新建态队列清空完毕\n");
	}
}

//取就绪队列的头结点进入运行态的队列
Status GetHeadAndCreateRunThread(LinkQueue* Q, QElemType e, QElemType e1, QElemType e2, QElemType e3)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	s->pcb.Pid = e;
	s->pcb.Priority = e1;
	s->pcb.Name = e2;
	s->pcb.Time = e3;
	s->pcb.State = 3;//设置进程的状态为运行态

	s->next = NULL;		/*新节点指向NULL*/
	Q->rear->next = s;  /*队尾指针的下一个元素指向新节点*/
	Q->rear = s;		/*队尾指针指向新节点(新节点成为队尾指针指向的节点)*/
	printf("运行态态: %d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);

	if (s->pcb.Time <= timeSlice)
	{
		printf("进程%d执行完毕,其所需的运行时间为%d\n", s->pcb.Name, s->pcb.Time);
		Queueptr p, q;			/*p用来遍历队列的节点,q用来指向被删除的节点*/

		Q->rear = Q->front;     /*队尾指针指向队头指针*/
		p = Q->front->next;     /*p指向队头指针的下一个节点*/
		Q->front->next = NULL;  /*队头指针的下一个节点指向NULL(表示删除之后的所有元素)*/

		//当队列中还有元素,释放头结点之后的所有节点
		while (p) {
			q = p;				/*q节点指向被删除节点*/
			p = p->next;		/*p指向队列的下一个节点*/
			free(q);			/*释放节点q*/
		}
	}
	else//进入阻塞队列
	{
		//取就运行态头结点给阻塞态,并且将运行态队列清空(用的是清空链队列的方法)
		Queueptr p, q;		    /*p用来遍历队列的节点,q用来指向被删除的节点*/

		Q->rear = Q->front;     /*队尾指针指向队头指针*/
		p = Q->front->next;     /*p指向队头指针的下一个节点*/
		Q->front->next = NULL;  /*队头指针的下一个节点指向NULL(表示删除之后的所有元素)*/

		//当队列中还有元素,释放头结点之后的所有节点
		while (p) {
			//由运行态创建阻塞态队列
			printf("因为时间片(timeSlice = 3)运行完毕所以进程:%d进入阻塞队列\n", p->pcb.Name);
			ClogThread(&clogQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, ((p->pcb.Time) - timeSlice));
			q = p;				/*q节点指向被删除节点*/
			p = p->next;		/*p指向队列的下一个节点*/
			free(q);			/*释放节点q*/
		}
		
	}
}

//创建阻塞态队列
Status ClogThread(LinkQueue* Q, QElemType e, QElemType e1, QElemType e2, QElemType e3)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	s->pcb.Pid = e;
	s->pcb.Priority = e1;
	s->pcb.Name = e2;
	s->pcb.Time = e3;
	s->pcb.State = 4;	/*设置进程状态为阻塞态*/

	s->next = NULL;     /*新节点指向NULL*/
	Q->rear->next = s;  /*队尾指针的下一个元素指向新节点*/
	Q->rear = s; 		/*队尾指针指向新节点(新节点成为队尾指针指向的节点)*/

	printf("%d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);
}

6.模块三:循环遍历阻塞态队列将进入阻塞态队列的每一个进程加入到就绪态队列中再送往运行态队列

//遍历阻塞态队列
Status QueueTravel1(LinkQueue* Q)//遍历clogQ(阻塞态)的队列
{
	Queueptr p;			/*用于遍历队列中的节点*/
	p = Q->front->next; /*p指向新建态队列的头结点*/

	while (p) {
		//将新建态队列的PCB内的信息复制到就绪队列相应的节点上
		EnQueue(&readyQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		p = p->next;	/*p移动到队列的下一个位置*/
	}

	//当阻塞态队列的PCB内的信息复制到就绪队列相应的节点上完成之后将阻塞态队列清空
	Queueptr n, m;
	Q->rear = Q->front;
	n = Q->front->next;
	Q->front->next = NULL;

	//当队列中还有元素,释放头结点之后的所有结点
	while (n) {
		m = n;
		n = n->next;
		free(m);
	}
	if (Q->front == Q->rear)
	{
		printf("阻塞态队列清空完毕\n");
	}
}

7.main

int main()
{

	int t = 0;//用于选择执行那一条过程
	InitQueue(&newbuiltQ);
	InitQueue(&runQ);
	InitQueue(&readyQ);
	InitQueue(&clogQ);

	while (t != 6)
	{
		printf("================================\n");
		printf("五状态进程的转换模拟\n");
		printf("================================\n");
		printf("1:创建新建态		2:模拟进程从就绪态到执行态再到阻塞态\n");
		printf("3:模拟将阻塞态态转为就绪态再转变到执行态		4:退出程序\n");
		printf("--------------------------------\n");
		printf("请选择(1~4):\n");
		scanf("%d", &t);
		switch (t) {
		case 1:	
				number++;
				EnQueueCreateThread(&newbuiltQ);
			break;
		case 2:
				QueueTravel(&newbuiltQ);
			break;
		case 3:
				QueueTravel1(&clogQ);
			break;
		case 4:
				printf("模拟过程结束Bye!\n");
				exit(0);
			break;
		}
	}
	return 0;
}

8.整合

//解决scanf返回值被忽略报错的问题,任选一个即可
#define _CRT_SECURE_NO_WARNINGS
//#pragma warning(disable:4996)

#include <stdio.h>
#include<stdlib.h>
#define error 0
#define ok 1

//全局变量
int timeSlice = 3;	//自定义时间片的长度
int number = 0;		//进程的数目

typedef int QElemType;
typedef int Status;

//节点的PCB信息
typedef struct PCB {
	QElemType Pid;			//进程的ID
	QElemType Priority;		//进程的优先级
	QElemType Name;			//进程的名称
	QElemType State;		//进程的状态 1为新建态 2为就绪态 3为运行态 4为阻塞态 5为退出态
	QElemType Time;			//进程需要运行的时间
	//int resoure[1];		//两种独占的资源
}PCB;

//链队列节点
typedef struct QNode {
	struct PCB pcb;			//节点所具有的信息
	struct QNode* next;		//指向下一个节点的指针
}QNode, * Queueptr;

//链队列结构
typedef struct {
	Queueptr front;		//队列的头指针
	Queueptr rear;		//队列的尾指针
}LinkQueue;

LinkQueue newbuiltQ;	//新建态进程队列
LinkQueue readyQ;		//就绪态进程队列
LinkQueue runQ;			//运行(执行)态进程队列
LinkQueue clogQ;		//阻塞态进程队列

//初始化队列
Status InitQueue(LinkQueue* Q)
{
	Q->front = Q->rear = (Queueptr)malloc(sizeof(QNode));
	if (!Q->front) return error; 	//申请空间失败
	Q->front->next = NULL;			//队头指向空
	return ok;
}

//创建一个新进程(建立新建态队列的方法),在队尾插入元素
Status EnQueueCreateThread(LinkQueue* Q)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	/*将PCB内的值赋值给新节点*/
	printf("请输入进程的ID号\n");
	scanf("%d", &s->pcb.Pid);
	printf("请输出进程的优先级\n");
	scanf("%d", &s->pcb.Priority);
	printf("请输入进程的名称\n");
	scanf("%d", &s->pcb.Name);
	s->pcb.State = 1;	//设置新建的进程为新建态
	printf("请输入进程需要运行的时间\n");
	scanf("%d", &s->pcb.Time);

	s->next = NULL;		//新节点指向NULL
	Q->rear->next = s;	//队尾指针的下一个元素指向新节点
	Q->rear = s;		//队尾指针指向新节点

	return ok;
}

Status EnQueue(LinkQueue* Q,QElemType e,QElemType e1, QElemType e2, QElemType e3)//创建就绪态队列在队尾插入元素
{
	
		Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
		if (!s)//分配失败
			exit(0);
		s->pcb.Pid = e;
		s->pcb.Priority = e1;
		s->pcb.Name = e2;
		s->pcb.Time = e3;
		s->pcb.State = 2;

		s->next = NULL;		//新节点指向NULL
		Q->rear->next = s;	//队尾指针的下一个元素指向新节点
		Q->rear = s;		//队尾指针指向新节点(新节点成为队尾指针指向的节点)
		printf("就绪态: %d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);

			//取就绪态头结点给运行态,并且将就绪态队列清空(用的是清空链队列的方法)
			Queueptr p, q;			//p用来遍历队列的节点,q用来指向被删除的节点

			Q->rear = Q->front;		//队尾指针指向队头指针
			p = Q->front->next;		//p指向队头指针的下一个节点
			Q->front->next = NULL;	//队头指针的下一个节点指向NULL(表示删除之后的所有元素)

			//当队列中还有元素,释放头结点之后的所有节点
			while (p) {
				//将p指向的节点信息以此送入运行态队列
				GetHeadAndCreateRunThread(&runQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
				
				q = p;		//q节点指向被删除节点
				p = p->next;//p指向队列的下一个节点
				free(q);	//释放节点q
		}

}

//遍历newbuild(新建态)的队列,将新建态队列中每一个节点的信息复制到就绪队列中
Status QueueTravel(LinkQueue* Q)
{	
	Queueptr p;			//用于遍历队列中的节点
	p = Q->front->next; //p指向新建态队列的头结点
	
	while (p) { 
		//printf("新建态:%d %d %d %d \n", p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		//将新建态队列的PCB内的信息复制到就绪队列相应的节点上
		EnQueue(&readyQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		p = p->next;	//p移动到队列的下一个位置
	}

	//当新建态队列的PCB内的信息复制到就绪队列相应的节点上完成之后将新建态队列清空
	Queueptr n, m;			//n用来遍历队列的节点,m用于指向被删除的节点
	Q->rear = Q->front;		//队尾指针指向队头指针
	n = Q->front->next;		//n指向队头指针的下一个节点
	Q->front->next = NULL;	//队头指针的下一个节点指向NULL(表示删除之后的所有元素)

	//当队列中还有元素,释放头结点之后的所有结点
	while (n) {
		m = n;			//m结点指向被删除节点
		n = n->next;	//n指向队列的下一个节点
		free(m);		//释放m节点
	}
	if(Q->front == Q->rear)
	{
		printf("新建态队列清空完毕\n");
	}
}

//取就绪队列的头结点进入运行态的队列
Status GetHeadAndCreateRunThread(LinkQueue* Q, QElemType e, QElemType e1, QElemType e2, QElemType e3)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	s->pcb.Pid = e;
	s->pcb.Priority = e1;
	s->pcb.Name = e2;
	s->pcb.Time = e3;
	s->pcb.State = 3;	//设置进程的状态为运行态

	s->next = NULL;		//新节点指向NULL
	Q->rear->next = s;	//队尾指针的下一个元素指向新节点
	Q->rear = s;		//队尾指针指向新节点(新节点成为队尾指针指向的节点)
	printf("运行态态: %d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);

	if (s->pcb.Time <= timeSlice)
	{
		printf("进程%d执行完毕,其所需的运行时间为%d\n", s->pcb.Name, s->pcb.Time);
		Queueptr p, q;	//p用来遍历队列的节点,q用来指向被删除的节点

		Q->rear = Q->front;		//队尾指针指向队头指针
		p = Q->front->next;		//p指向队头指针的下一个节点
		Q->front->next = NULL;	//队头指针的下一个节点指向NULL(表示删除之后的所有元素)

		//当队列中还有元素,释放头结点之后的所有节点
		while (p) {
			q = p;			//q节点指向被删除节点
			p = p->next;	//p指向队列的下一个节点
			free(q);		//释放节点q
		}
	}
	else//进入阻塞队列
	{
		//取就运行态头结点给阻塞态,并且将运行态队列清空(用的是清空链队列的方法)
		Queueptr p, q;			//p用来遍历队列的节点,q用来指向被删除的节点

		Q->rear = Q->front;		//队尾指针指向队头指针
		p = Q->front->next;		//p指向队头指针的下一个节点
		Q->front->next = NULL;	//队头指针的下一个节点指向NULL(表示删除之后的所有元素)

		//当队列中还有元素,释放头结点之后的所有节点
		while (p) {
			//由运行态创建阻塞态队列
			printf("因为时间片(timeSlice = 3)运行完毕所以进程:%d进入阻塞队列\n", p->pcb.Name);
			ClogThread(&clogQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, ((p->pcb.Time) - timeSlice));
			q = p;				//q节点指向被删除节点
			p = p->next;		//p指向队列的下一个节点
			free(q);			//释放节点q
		}
		
	}
}

//创建阻塞态队列
Status ClogThread(LinkQueue* Q, QElemType e, QElemType e1, QElemType e2, QElemType e3)
{
	Queueptr s = (Queueptr)malloc(sizeof(QNode));//给新节点分配空间
	if (!s)//分配失败
		exit(0);
	s->pcb.Pid = e;
	s->pcb.Priority = e1;
	s->pcb.Name = e2;
	s->pcb.Time = e3;
	s->pcb.State = 4;	//设置进程状态为阻塞态

	s->next = NULL;		//新节点指向NULL
	Q->rear->next = s;	//队尾指针的下一个元素指向新节点
	Q->rear = s;		//队尾指针指向新节点(新节点成为队尾指针指向的节点)

	printf("%d %d %d %d \n", s->pcb.Pid, s->pcb.Priority, s->pcb.Name, s->pcb.Time);
}

//遍历阻塞态队列
Status QueueTravel1(LinkQueue* Q)//遍历clogQ(阻塞态)的队列
{
	Queueptr p;			//用于遍历队列中的节点
	p = Q->front->next; //p指向新建态队列的头结点

	while (p) {
		//printf("新建态:%d %d %d %d \n", p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		//将新建态队列的PCB内的信息复制到就绪队列相应的节点上
		EnQueue(&readyQ, p->pcb.Pid, p->pcb.Priority, p->pcb.Name, p->pcb.Time);
		p = p->next;//p移动到队列的下一个位置
	}

	//当阻塞态队列的PCB内的信息复制到就绪队列相应的节点上完成之后将阻塞态队列清空
	Queueptr n, m;			//n用来遍历队列的节点,m用于指向被删除的节点
	Q->rear = Q->front;		//队尾指针指向队头指针
	n = Q->front->next;		//n指向队头指针的下一个节点
	Q->front->next = NULL;	//队头指针的下一个节点指向NULL(表示删除之后的所有元素)

	//当队列中还有元素,释放头结点之后的所有结点
	while (n) {
		m = n;				//m结点指向被删除节点
		n = n->next;		//n指向队列的下一个节点
		free(m);			//释放m节点
	}
	if (Q->front == Q->rear)
	{
		printf("阻塞态队列清空完毕\n");
	}
}

int main()
{

	int t = 0;//用于选择执行那一条过程
	InitQueue(&newbuiltQ);
	InitQueue(&runQ);
	InitQueue(&readyQ);
	InitQueue(&clogQ);

	while (t != 4)
	{
		printf("================================\n");
		printf("五状态进程的转换模拟\n");
		printf("================================\n");
		printf("1:创建新建态		2:模拟进程从就绪态到执行态再到阻塞态\n");
		printf("3:模拟将阻塞态态转为就绪态再转变到执行态		4:退出程序\n");
		printf("--------------------------------\n");
		printf("请选择(1~4):\n");
		scanf("%d", &t);
		switch (t) {
		case 1:	
				number++;
				EnQueueCreateThread(&newbuiltQ);
			break;
		case 2:
				QueueTravel(&newbuiltQ);
			break;
		case 3:
				QueueTravel1(&clogQ);
			break;
		case 4:
				printf("模拟过程结束Bye!\n");
				exit(0);
			break;
		}
	}
	return 0;
}

9.调试截图

在这里插入图片描述
这里是创建了三个进程在这里插入图片描述
[参考文档]链队列:(https://blog.csdn.net/ningjinghai11/article/details/89306422?utm_source=app&app_version=4.7.1&code=app_1562916241&uLinkId=Usr1mkqgl919blen)

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值