作业二:进程PCB管理与调度程序

作业二:进程PCB管理与调度程序

系统管理进程在系统中各种运行活动都离不开对于进程PCB的操作,本次作业以进程的PCB为管理目标,实现进程调度时状态变化相应的操作。

作业描述

使用数据结构struct PCB表示进程,记录进程的相关信息;进程信息包括:进程内部标识符pid、进程名pname、进程状态pstatus、

进程运行时间ptime、进程队列指针pnext。请设计合理的数据结构,容纳这些信息,以下是示例代码。

 

#define RUNNING0  /* 执行  */    

#define READY1  /* 就绪  */    

#define FINISHED2  /* 结束 */    

#define EMPTY3  /* PCB表空闲  */        

struct PCB    {    

	int  pid;        

	char pname[8];        

	int  pstatus;        

	int  ptime;        

	PCB *pnext;

};

 

 

设置三个队列(链表),分别是就绪队列、执行队列和空闲PCB队列。

程序初始化的时候先创建空闲PCB队列,然后根据用户输入的进程数量创建进程并构成进程就绪队列。

使用链表表示进程所在队列。

进程按着顺序轮流执行,每个进程一次执行m个时间片,m大于等于1。

进程PCB中的ptime初始值是进程运行完毕需要的时间,初始值可以随机赋值一个整数,运行过程中每运行一次则:

    ptime = ptime - m;    if (ptime<=0)         执行-->完成;  /* 进程从执行态转变为完成 */

直到ptime小于或等于0表示该进程可以在最后一次分配的时间片中执行完毕。

编写基本管理函数,包括添加insert_pcb()、删除del_pcb()、修改mod_pcb()。

进程调度及状态变化时屏幕打印相关信息。

这里是一个例子程序(点击下载),如果你不太明白题目的意思,可以运行这个例子程序,看看输出结果你是否能够看明白。

背景知识

1. 进程控制块PCB。PCB是进程的重要数据结构,包括了重要的控制信息,如进程标识、处理机现场、进程状态、资源列表等。

2. 队列与链表。使用链表操作实现队列中节点的添加、修改和删除。

3. 进程状态。进程的基本状态包括执行、就绪和阻塞三种,引入挂起后,变为执行、活动就绪、活动阻塞、静止就绪和静止阻塞等。

进程在生命周期中的活动就是在这些状态上进行变化。

 

 

/*----------------------------------------------------------------------------------------------------------------*/

实现如下:

作业二:进程PCB管理与调度程序

下面代码基本是基于进程控制块的组织方式(a.链接方式 )- 来实现的。

程序实现比较简化,如没有阻塞队列等。

基于如图的这种结构,即认为-系统开辟的PCB区为连续的存储结构来存储。

故以下代码是基于静态链表(空闲PCB队列,就绪队列)来实现的,

因为如图的这种结构,在用数据结构模拟的前提下,若用动态指针(PCB若指针链式连接,则动态较好),反而可能显得臃肿。

主要思路能显得清晰即可。

代码如下:

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <ctime>

#include <iostream>

using namespace std;

#ifdef LINUX

#include <unistd.h>

#define SLEEP(N) sleep(N)

#endif



#ifdef WIN32

#include <windows.h>

#define SLEEP(N) Sleep(N)

#endif

#define NUM 6//默认系统PCB区有6个PCB 

int each_time = 1;

int N = 0;

char sname[6][3] = {"p1", "p2", "p3", "p4", "p5", "p6"}; 



typedef enum {

	RUNNING,

	READY,

	FINISHED,

	EMPTY

}Pstatus; //记录进程状态的枚举类型 



typedef struct Process { 

	int  pid;

	char pname[8];

	int  pstatus;

	int  ptime;

	int pnext;

	

	Process() {

		pid = -1;

		pstatus = EMPTY;

		ptime = 0;

		pnext = -1;

		memset(pname, 0, sizeof(pname));	

	}

}Process;

Process PCB[NUM], Pre_PCB[NUM];



typedef struct Pqueue {

	int top;

	int rear;

}Pqueue;

Pqueue ready, pre_ready;

Pqueue pfree;

int run, pre_run;



void Creat_Pcb(int pid) {

	PCB[pid].pstatus = READY;

	strcpy(PCB[pid].pname, sname[N++]);

	PCB[pid].ptime = rand() % 8 + 1;

	PCB[pid].pnext = -1;

}//分配PCB给进程 



void Push_Pqueue(int pid, Pqueue &cur) {

	if(cur.top == -1) {

		cur.top = pid;

	} else {

		PCB[cur.rear].pnext = pid;

	}

	cur.rear = pid;

	PCB[cur.rear].pnext = -1;

}//压入队列,就绪队列或空闲队列 



int Pop_Pqueue(Pqueue &cur) {

	if(cur.top == -1) {

		printf("队列为空,ERROR。\n");

		return -1;

	}

	int pid = cur.top;

	cur.top = PCB[pid].pnext;

	if(cur.top == -1) {

		cur.rear = -1;

	}

	PCB[pid].pnext = -1;

	return pid;

}//弹出队列 



void Del_Pcb(int pid) {

	PCB[pid].ptime = 0;

	PCB[pid].pnext = -1;

	Push_Pqueue(pid, pfree);

}//回收PCB,恢复到空闲状态 



void Insert_Pcb() {

	if (pfree.top == -1) {

		puts("空闲队列为空, 创建进程失败");

		return ; 

	}

	int pid = Pop_Pqueue(pfree);//从空闲PCB队列取出PCB 

	Creat_Pcb(pid);//分配PCB给进程 

	Push_Pqueue(pid, ready);//进入就绪队列 

}//创建进程 



void Print_Status(Process state[], Pqueue cur, int ran); 

void Modify_Pcb() {//进程调度 

	if (ready.top == -1) {

		puts("系统没有进程可以调度");

		return ; 

	}

	pre_run = run;

	pre_ready = ready;

	int pid = Pop_Pqueue(ready);

	run = pid;

	PCB[pid].pstatus = RUNNING;

	

	puts("上一步状态:");

	Print_Status(Pre_PCB, pre_ready, pre_run);

	puts("当前状态:");

	Print_Status(PCB, ready, run);//输出状态 

	for (int i = 0; i < N; i++) {

		Pre_PCB[i] = PCB[i];

	}//保存当前状态的前驱。 

	if (PCB[pid].ptime - each_time > 0) {

		PCB[pid].ptime -= each_time; 

		PCB[pid].pstatus = READY;	

		Push_Pqueue(pid, ready);

	} else {

		PCB[pid].ptime = 0;

		PCB[pid].pstatus = FINISHED;

		Del_Pcb(pid);

	}//修改PCB状态,保存现场(这里仅ptime) 

} 



void Init_Pcb() {

	int i;

	N = 0;

	each_time = rand() % 6 + 1;//随机生成时间片大小 

	for (i = 0; i < NUM; i++) {

		PCB[i].pid = i;

		PCB[i].pnext = i + 1;

	}

	

	PCB[NUM-1].pnext = -1;

	pfree.top = 0;

	pfree.rear = NUM - 1;

	ready.top = -1;

	ready.rear = -1; 

	run = -1;

}//系统PCB区的初始化状态 



void Print_Status(Process state[], Pqueue cur, int ran) {

	puts("╔═══════════════════════╗"); 

	puts("║    进程名     进程状态    进程剩余执行时间   ║");

	for (int i = 0; i < N; i++) {

		printf("║\t%s\t", state[i].pname);

		switch(state[i].pstatus) {

			case RUNNING: printf(" RUNNING\t");break;

			case READY: printf(" READY\t\t");break;

			case FINISHED: printf(" FINISHED\t");break;

			default:break; 

		}

		printf("%d\t\t║\n", state[i].ptime);

	} 

	puts("╚═══════════════════════╝"); 

	printf("╠═  Ready_queue :");

	for (int i = cur.top; i != -1; i = state[i].pnext) 

		printf(" %s ->", state[i].pname);

	printf(" NULL\n");

	printf("╠═  Active_queue:");

	if (ran != -1) printf(" %s ->", state[ran].pname);

	puts(" NULL");

}//输出状态函数 



void speed(int v) {

	switch(v) {

		case 1: 

			SLEEP(500);

			break;

		case 2: 

			SLEEP(1600);

			break;

		case 3: 

			SLEEP(2400);

			break;

		default: break;

	}

}//自动演示模式的分档(停顿间隔)函数 



int Check_Input(char str[]) {

    int i, k = 0;

    int st = -1, ed = -1;

    char stmp[110];

   	for (i = 0; str[i]; i++) if (str[i] != ' ') {st = i; break;}

   	for (i = strlen(str) - 1; i >= 0; i--) if (str[i] != ' ') {ed = i; break;}

 	if (st == -1) return -2;

    for (i = st; i <= ed; i++) {

        if (!(str[i] >= '0' && str[i] <= '9')) {

            return -1;

        } else {

            stmp[k++] = str[i];    

        }

    }

    int r = 1, sum = 0;

    for (i = k - 1; i >= 0; i--, r *= 10) {

        sum += (stmp[i] - '0') * r;

    }

    return sum;

}//输入处理,做简单的排错处理



void solve() {

	int n;

	char str[110];

	puts("输入进程的数量(范围在[1-6]内):");

	while (gets(str)) {

		while ((n = Check_Input(str)) < 0 || n > 6) {

			if (n == -1 || n > 6) {//输入检查处理

				puts("ERROR, 请重新输入");

			}

			gets(str); 

		} 

		Init_Pcb();//初始化 

		for (int i = 0; i < n; i++) {

			Insert_Pcb();

		}

		for (int i = 0; i < n; i++) {

			Pre_PCB[i] = PCB[i];

		}//保存前一个状态的信息 

		puts("初始进程情况:");

	 	Print_Status(PCB, pre_ready, run);

	 	printf("╠═  时间片大小为 %d\n", each_time);

		int mode = 1;

		int v = 1;

		puts("\n请选择演示模式:1(自动)   2(手动)");

		gets(str); 

		while (! ((mode = Check_Input(str)) >= 1 && mode <= 2) ) {

			if (mode != -2) {

				puts("ERROR, 请重新输入");//输入检查处理

			}

			gets(str);

		}	 

		if (mode == 1) {

			puts("1:快速演示\t2:中速演示\t3:慢速演示");

			gets(str);

			while (! ((v = Check_Input(str)) >= 1 && v <= 3) ) {

				if (v != -2) {

					puts("ERROR, 请重新输入");//输入检查处理

				}

				gets(str);

			}

		}

		

		while (true) {

			system("cls"); 

			Modify_Pcb();//进程调度 

			if (ready.top == -1) {//就绪队列空。 

				if (mode == 2) { 

					puts("点击前往下一步");

					system("pause");

				}

				break;

			}		

			if (mode == 1) {

				speed(v);//自动模式停顿 

			} else {

				puts("点击前往下一步");

				system("pause");//以完成手动模式手动翻页 

			}

		}

		if (mode == 1) speed(v);//自动模式停顿 

		system("cls");

		puts("上一步状态:");

		Print_Status(Pre_PCB, ready, run);

		puts("当前状态:");

		for (int i = 0; i < n; i++) PCB[i].pstatus = FINISHED;

		run = -1;

		Print_Status(PCB, ready, run);//完成状态 

		puts("congratulation!!!进程全部成功运行结束!");

		system("pause");

		system("cls");

		puts("输入进程的数量(范围在[1-6]内):");

	}

}



int main() {

	srand((unsigned)time(NULL));

	solve();

	return 0;

}

以下是上面代码的.exe可执行文件(传不上去,rar压缩文件)。

点击 下载

 

12.5号 - 重新写了个PCB用指针链式连接的程序,伪界面简单一些。

此程序的特点主要是简单易懂一些,简化了一些浮云的处理;

叹自己平时都不用指针的,用起指针来就显得比较生疏,过程中出现诸如内存不可读很多次。

不过最后程序还算清晰,调度函数Modify_Pcb()相对上面程序而言写的要清晰一些。

  (上面的写的戳了,最后一次输出要特殊到外面处理,这里就不需要-)。

代码如下:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <time.h>

#define NUM 6

#define RUNNING 0  /* 执行  */    

#define READY 1  /* 就绪  */    

#define FINISHED 2  /* 结束 */    

#define EMPTY 3  /* PCB表空闲  */   

int each_time = 1;//默认时间片为1 

int N = 0;

char sname[6][3] = {"p1", "p2", "p3", "p4", "p5", "p6"};

     

typedef struct PCB {    

	char pname[8];        

	int  pstatus;        

	int  ptime;        

	PCB *pnext;

}PCB, *QueuePtr;



typedef struct {

	QueuePtr front;

	QueuePtr rear;

}LinkQueue;  

LinkQueue p_empty, p_ready, p_run, p_end;



void InitQueue(LinkQueue &Q) {

	Q.front = Q.rear = (QueuePtr)malloc(sizeof(PCB));

}//初始化队列 



void EnQueue(LinkQueue &Q, QueuePtr p) {

	Q.rear->pnext = p;

	Q.rear = p;

	p->pnext = NULL;

}//压入队列 



void DeQueue(LinkQueue &Q, QueuePtr &p) {

	if (Q.front == Q.rear) {

		printf("ERROR,队列为空!");

	}

	p = Q.front->pnext; 

	Q.front->pnext = p->pnext;

	p->pnext = NULL;

	if (Q.rear == p) Q.rear = Q.front;

}//出队列,将出队元素的结点指针用p保存 



void Insert_Pcb() {

    QueuePtr p;

   	DeQueue(p_empty, p);//从空闲队列取出PCB 

	EnQueue(p_ready, p); //加入到就绪队列 

	strcpy(p->pname, sname[N++]);

	p->pstatus = READY;

	p->ptime = rand() % 8 + 1;//初始化信息,名字,状态

	//进程执行时间(rand随机生成,rand() %8+1后在1-8范围)

	printf("创建进程%s,执行时间%d     <创建成功>\n", p->pname, p->ptime);

}//创建进程 



void Del_Pcb(QueuePtr &p) {

	p->ptime = 0;

	p->pstatus = FINISHED;

	p->pnext = NULL;

	EnQueue(p_end, p);

}//删除进程,加入到完成状态队列中。 



void Modify_Pcb() {//进程调度 

	QueuePtr cur;

	puts("===============执行调度=============");

	if (p_run.front != p_run.rear) {//执行队列不空 

		DeQueue(p_run, cur);//弹出执行进程 

		cur->ptime -= each_time;//执行一个时间片 

		printf("调度:进程%s     ", cur->pname);

		if (cur->ptime > 0) {//若执行未结束,经调度到就绪状态 

			cur->pstatus = READY;

			printf("<执行 -> 就绪>.\n");

			EnQueue(p_ready, cur);

		}

		else {//执行结束 

			printf("<执行 -> 结束>.\n");

			Del_Pcb(cur);//加入到结束队列 

		}

	}

	if (p_ready.front != p_ready.rear) {//就绪队列不空 

		DeQueue(p_ready, cur);//弹出就绪队列队首元素 

		EnQueue(p_run, cur);//进入执行态 

		cur->pstatus = RUNNING;

		printf("调度:进程%s     <就绪 -> 执行>.\n", cur->pname);

		printf("调度:%s执行中...\n", cur->pname);//调度执行 

		printf("就绪队列 : ");

		QueuePtr ready = p_ready.front->pnext;

		while (ready) {

			printf("%s<1>->", ready->pname);

			ready = ready->pnext;

		}//输出就绪队列 

		puts("NULL");

		printf("执行队列 : ");

		printf("%s<0>->NULL\n\n", cur->pname);//输出执行队列 

	}

}



void Init_PCB() {

	InitQueue(p_empty);

	InitQueue(p_ready);

	InitQueue(p_run);

	InitQueue(p_end);//初始化队列 

	for (int i = 0; i < NUM; i++) {

		QueuePtr p = (QueuePtr)malloc(sizeof(PCB)); 

		p->pnext = NULL;

		EnQueue(p_empty, p);

	}//初始空闲队列为6个空闲PCB 

}



void solve() {

	int n;

	printf("进程数量?[1-6]:");

	scanf("%d", &n);

	if (n < 1 || n > 6) { puts("输入数据不在1-6"); return ; } 

	Init_PCB();//初始化队列 

	for (int i = 0; i < n; i++) {

		Insert_Pcb();//创建进程 

	}

	

	while (true) {

		Modify_Pcb();//进程调度(若就绪队列不空,调度后p_run不为空) 

		if (p_run.front == p_run.rear) {

			break;//没有进程在执行时退出。 

		}

	}

	QueuePtr run;

	printf("结束队列 : ");

	QueuePtr end = p_end.front->pnext;

	while (end) {

		printf("%s<1>->", end->pname);

		end = end->pnext;

	}

	puts("NULL");//输出结束队列(按结束次序) 

}



int main() {

	srand((unsigned)time(NULL));//以时间做随机种子

	solve();

	return 0;

} 

 

原创文章如转载请注明:转自¥忘%风 {http://www.cnblogs.com/slave_wc}

本文地址: 作业二:进程PCB管理与调度程序

你可能感兴趣的:(管理)