操作系统作业02

来源:互联网 发布:tcl网络电视怎么打开 编辑:程序博客网 时间:2024/05/22 01:21

操作系统作业02


题目

请编写一个程序,模拟若干进程调度执行的情况。假设进程的状态分为执行和就绪两种。每个进程以其PCB为代表即可,无需创建真正的进程。

以链表的方式组织PCB,分为三个队列: freeQueue:一个空白PCB队列 readyQueue:一个就绪队列
runningQueue:一个执行队列

程序开始运行时,用户输入进程数量n,以及每个进程需要运行的时间t0/t1/…/tn。程序从空白PCB队列中取出PCB创建进程,插入readyQueue。

进程的调度采用随机的方式,即从就绪队列中随机选择一个进程投入运行(就是将该PCB中的状态变量赋值为“运行”)。相应的修改其所在队列,并且原来处于运行态的进程需要转变为“就绪”态,插入readyQueue。

假设时间片是2,进程每次调度运行后,其还需运行的时间应该减少2,直至为0,即表示该进程执行完毕。需要回收PCB到freeQueue。

每次发生调度的时候,需要打印信息示例: Sched: P0(Running -> Ready), P3(Ready -> Running)
Running: P3 Ready: P1->P2->P0
上述信息表示调度时P0处于运行态,选择P3运行,P0进程的PCB进入就绪队列,并且在队尾。就绪队列是按照队列节点次序输出进程名称。
示例片段代码:

#define free 0
#define ready 1
#define running 2
#define ts 2 /* time slice */ struct PCB {
int pid; /* 进程ID */
int pstate; /* 进程状态 */
char pname; / 映象名称 */
int ptime; /* 剩余运行时间 */
struct PCB pnext; / 下一个PCB */ }

代码实现

#include<stdio.h>#include<malloc.h>#include <string.h>#include<stdlib.h>#include<time.h>#define free 0#define ready 1#define running 2#define ts 2 /* time slice */struct PCB {    int pid;    /* 进程ID  */    int pstate;  /* 进程状态 */    char pname[20]; /* 映象名称 */    int ptime;   /* 剩余运行时间 */    struct PCB *pnext;  /* 下一个PCB */};/*产生随机数并用于随机调度*/int PCBchange(int isEmpty[],int run,int PCB_num){    int lrun = rand()%PCB_num;    while(run==lrun || isEmpty[lrun]<0){                //获取随机调度目标id,并防止重复        lrun = rand()%PCB_num;    }    return lrun;}/*在就绪队列查找调度目标并完成切换*/struct PCB * findAndSwitch(int Id,struct PCB * tp,struct PCB * sp){    struct PCB * getP;    struct PCB * temp;    getP = tp;    //寻找调度进程的位置    while(getP->pnext!=NULL&&getP->pnext->pid != Id){        getP = getP->pnext;    }    /*就绪队列以及运行队列的进程切换*/        temp = getP->pnext;    if(temp->pnext!=NULL){        getP->pnext = temp->pnext;  //readyQueue链表操作    }else{        getP->pnext = NULL;    }    getP = sp->pnext;    sp->pnext = temp; //连接到running链表中    temp->pnext = NULL;         //清零后续位    return getP;}/*输出readyQueue*/void outputReady(struct PCB* tp){    struct PCB* getP;    printf("Ready:");    if(tp->pnext!= NULL){        getP = tp->pnext;        printf("%s",getP->pname);   //输出首个元素        getP = getP->pnext;        while(getP!=NULL){          //循环输出后续元素            printf("->%s",getP->pname);            getP = getP->pnext;        }        printf("\n");    }else        printf("NULL\n");}int main(){    struct PCB * freeQueue = (struct PCB*)malloc(sizeof(struct PCB));    struct PCB * readyQueue = (struct PCB*)malloc(sizeof(struct PCB));    struct PCB * runningQueue = (struct PCB*)malloc(sizeof(struct PCB));    struct PCB * temp;                     //辅助操作指针    struct PCB * getP;                      //同上    int PCB_num;                        //储存进程数量    char str[10];                       //初始化各进程name    int isEmpty[50]={0};                //记录各进程是否执行完毕的数组    int i=0;                            //辅助参数    int run=-1;                         //储存随机调度目标id    int counter = 0;                    //记录已运行完毕进程的数量    int isComplete=1;                   //主循环是否继续的标志位    srand((unsigned) time(NULL));   //产生种子用于随机调度    /*初始化POB*/    runningQueue->pnext = NULL;    printf("请输入进程数量:");    scanf("%d",&PCB_num);    printf("请依次输入每个进程运行耗时:");    getP = freeQueue;    for(i;i<PCB_num;i ){        temp = (struct PCB*)malloc(sizeof(struct PCB));     //请求动态储存空间        temp->pid = i;                              //记录id        temp->pstate = 0;                           //初始化状态        sprintf(str, "%d" , i);                     //name操作        memset(temp->pname, 0, 20);                 //初始化字符串        temp->pname[0] = 'P';        strcat(temp->pname, str);        scanf("%d",&(temp->ptime));                 //输入进程运行所需时间        temp->pnext = NULL;                         //初始化pnext指针        getP->pnext = temp;                         //链表连接        getP = getP->pnext;        isEmpty[i] = i;                             //初始化记录数组    }    /*转换到就绪队列*/    readyQueue->pnext = freeQueue->pnext;       //进入就绪队列    freeQueue->pnext = NULL;    /*运行并随机调度*/    while(isComplete){        run = PCBchange(isEmpty, run, PCB_num);       //获取随机值        if(runningQueue->pnext==NULL){            /*首次运行*/            getP = findAndSwitch(run,readyQueue,runningQueue);     //定位目标进程并完成切换            /*输出*/            printf("Sched:%s(Ready->Running)\n",runningQueue->pnext->pname);            printf("Running:%s\n",runningQueue->pnext->pname);            outputReady(readyQueue);        }        /*判断调度是否是自己*///        else if(run==runningQueue->pnext->pid){//            printf("Sched:%s(Running->Runing)\n",runningQueue->pnext->pname);//            printf("Running:%s\n",runningQueue->pnext->pname);//            outputReady(readyQueue);//        }        /*后续运行*/        else{            getP = findAndSwitch(run, readyQueue, runningQueue);  //定位目标进程并完成切换            temp = readyQueue;              //连接到readyQueue链表尾部            while(temp->pnext!=NULL)                temp = temp->pnext;            temp->pnext = getP;             //将进入就绪队列的进程放在队尾            /*输出*/            printf("Sche:%s(Running->Ready),%s(ready->Running)\n",                   getP->pname,runningQueue->pnext->pname);            printf("Running:%s\n", runningQueue->pnext->pname);            outputReady(readyQueue);            }        runningQueue->pnext->ptime -= 2;        //进程时间-2        /*将就绪队列中运行完毕的进程转到空队列*/        for(i=0;i<PCB_num; i){            if(isEmpty[i] == -1)            {                isEmpty[i] = -2;                temp = readyQueue;                while(temp->pnext->pid != i)                    temp = temp->pnext;                if(temp->pnext!=NULL){                    getP = temp->pnext;                    temp->pnext = getP->pnext;                }else{                    getP = temp->pnext;                    temp->pnext = NULL;                }                    getP->pnext = freeQueue->pnext; //free链表连接                    freeQueue ->pnext = getP;                printf("Sche:%s(Ready->free)\n",getP->pname);                counter ;                      //已完成进程数量加一            }        }        if(runningQueue->pnext->ptime<=0){      //判断运行进程是否运行完毕            isEmpty[run] = -1;        }        if(counter == PCB_num-1){               //判断所有进程是否运行完毕            printf("Sche:%s(Ready->free)\n",runningQueue->pnext->pname);            isComplete = 0;        }    }    return 0;}

运行结果

输入4个进程的实际运行结果
这里写图片描述


小结

本次作业,发现了很多不足,比如在链表操作时经常遇到空指针问题,代表自己的指针操作还是不甚熟料,同时,犯了上手就写代码的错误,导致后期很多链表操作的代码重复,以至于后期不易调试导致我几乎重写把链表全都封到函数中,不过就算现在的代码逻辑也不是很清晰,下次一定要先构思再下手

1 0