一个小MM让我帮忙弄个课程设计,虽然挺简单但还是想了比较久才搞定(去网上搜索的代码都有明显的bug),重点是 SortChain 函数。 如果是双向链表估计就好
处理了:
(1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:
其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。
指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。
要求运行时间——假设进程需要运行的单位时间数。
优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。
(3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例:
队首标志
(4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行:
优先数-1
要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。
(5) 进程运行一次后,若要求运行时间不为¹0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。
(6) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。
(7) 在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。
(8) 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
原理简单,不多讲解了,直接放上代码吧:
#include<stdio.h> #include<stdlib.h> #include<time.h> struct PCB *head,*tail; ///这里是全局的 int global_time = 0;//全局时间 //定义结构体,包含五个属性,名字,下一个PCB指针,运行时间,优先级,目前状态 struct PCB{ char name[10]; struct PCB *next; int run_time; int priority; char status; }; struct PCB* initPCB(struct PCB *p, int i) { p->name[0] = 'P'; p->name[1] = i + '0'; p->name[2] = 0; p->next = NULL; printf("Process %s\n", p->name); printf("input run_time: "); scanf("%d", &p->run_time); printf("input priority: "); scanf("%d", &p->priority); /*p->run_time = i+1; p->priority = i; p->status = 'R';*/ return p; } //输入任务名称, 时间和优先级,运行状态为E void run(struct PCB *p) { printf("Process: %s, running @ tim %d, priority %d, run_time %d\n", p->name, global_time, p->priority, p->run_time); global_time++; p->run_time--; if(p->priority > 0) /// 优先级不可能出现负值吧!! p->priority--; } //输出这个任务的状态,全局时间加1,任务还需要的时间减1,优先级减1 /// 这里的时间复杂度挺高的,不知可不可以用特别的方式优化下 ?? void SortChain(struct PCB *phead,struct PCB *ptail) { struct PCB *pMax,*pMaxPre,*pPre,*pTemp; head = tail = NULL; /// 再初始化一次,重新把排列好的结点加入到链表中 pPre = pMax = pMaxPre = NULL; /// pMax:priority 最大的那个结点, pMaxPre:pMax前个结点 或许用双向链表更好一些 if(phead == NULL){ head = tail = NULL; return ; }else{ while(phead != NULL){ pMax = phead; pMaxPre = phead; for(pTemp = phead;pTemp != NULL; pTemp = pTemp->next){ if(pTemp->priority > pMax->priority ){ pMax = pTemp; pMaxPre = pPre; } pPre = pTemp; } if(pMax == phead){ phead = phead->next; }else{ pMaxPre->next = pMax->next ; } pMax ->next = NULL; if(head == NULL){ tail = head = pMax; }else{ tail -> next = pMax; tail = pMax; } } } } int main(void ) { int i; struct PCB *p = NULL, *q = NULL; //定义 指针p和q,p为待运行队列PCB指针,q为待插入队列PCB指针 head = tail = NULL; for(i = 0;i < 5;i ++){ p = (struct PCB *)malloc(sizeof(struct PCB)); //分配空间,让p指向这个PCB initPCB(p,i); p -> next = NULL; if(head == NULL){ /// 首先把进程 链表排列起来! 不一定按照 priority 顺序 tail = head = p; }else{ tail -> next = p; tail = p; } } SortChain(head,tail); /// 按照 priority 顺序 排列结点 while(head != NULL){ //当头节点不为空即链表中还有PCB的时候 printf("Current state:\n"); for(p = head; p != NULL; p = p->next){ printf("Process %s, priority: %d, run_time %d\n", p->name, p->priority, p->run_time); }//让p指针从 head->next 开始走到末尾,输出每一个状态 p = head; run(p);//p指向第一个PCB,然后进行调度 if(p->run_time <= 0){ printf("Process %s ends.\n", p->name); p->status = 'E'; ///free(p); ///这里就不释放了 head = p-> next; }//如果PCB已经结束,输出信息,释放空间 ,进行下一轮循环 SortChain(head,tail); /// 按照 priority 顺序 排列结点 }//如果还需要运行,将PCB插入合适位置 system("pause"); return 0; }