一、实验目的:

熟悉处理器调度算法的工作原理,掌握调度算法的实现、进程的状态及状态转换。具体如下:

  1. 设计并实现模拟进程调度的算法:时间片轮转调度算法。
  2. 理解进程控制块的结构。
  3. 理解进程运行的并发性。
  4. 掌握进程调度算法。

二、实验内容:

在多道程序运行环境下,进程数目一般多于处理机数目,使得进程要通过竞争来使用处理机。这就要求系统能按某种算法,动态地把处理机分配给就绪队列中的一个进程,使之运行,分配处理机的任务是由进程调度程序完成的。一个进程被创建后,系统为了便于对进程进行管理,将系统中的所有进程按其状态,将其组织成不同的进程队列。于是系统中有运行进程队列、就绪队列和各种事件的进程等待队列。进程调度的功能就是从就绪队列中挑选一个进程到处理机上运行。进程调度的算法有多种,常用的有优先级调度算法、先来先服务算法、时间片轮转算法。
进程是程序在处理机上的执行过程。进程存在的标识是进程控制块

PCB进程控制块结构

typedef struct PCB 
{ 
   int id;                            /* 进程id */
   char name[10];                    /* 进程标识符 */ 
   int allTime;                       /* 进程共需要占用 CPU 时间 */ 
   int needTime;                      /* 进程到完成还需要的时间 */ 
   int cpuTime;                      /* 进程已经占用CPU的时间 */
   int startBlock;                      /* 开始阻塞的时刻,-1表示不会发生阻塞*/
   int blockTime;                      /* 阻塞消耗的总时间 */
   char state;                        /* 进程的状态:就绪、阻塞、运行、完成*/ 
    struct node *next                   /*链指针*/ 
}PCB; 

系统创建一个进程,就是由系统为某个程序设置一个PCB,用于对该进程进行控制和管理,进程任务完成,由系统收回其PCB,该进程便消亡。每个进程可以有四个状态:运行状态、就绪状态、阻塞状态和完成状态。
用C语言编写一个程序实现进程调度的算法,模拟进程调度的过程,加深对进程控制块概念和进程调度算法的理解。

设计要求:

  1. 进程的调度采用时间片轮转算法。
  2. 设计3个链队列,分别用来表示就绪队列、阻塞队列和完成队列。
  3. 进程的相关信息通过一个文本文件的形式传给程序,程序在接受到进程的信息后,为每个进程申请空间并存放进进程控制块PCB中。文本文件的内容自行设置。
  4. 为了清楚的观察各个进程的调度过程,每当有进程状态变化时,程序应该将所有进程当前的状态显示出来,一直到所有进程运行完成为止。具体参照如下的格式:

各个就绪进程的信息如下:
在这里插入图片描述

时间片轮转调度的基本原理:系统将所有就绪的进程按先来先服务的原则排成一个就绪队列。系统设置每一个时间间隔便产生一次中断,去激活进程调度程序进行调度,把CPU分配给队首进程,并令其执行一个时间片。当它运行完毕后,又把处理机分配给就绪队列中新的队首进程,也让它执行一个时间片。这样,就可以保证就绪队列中的所有进程在确定的时间段内,都能获得一个时间片的处理机时间。
在时间片轮转调度算法中,触发进程调度有如下几种情况:○1若一个时间片尚未用完,正在运行的进程便已经完成,就会立即激活调度程序,将它从就绪队列中删除,再调度就绪队列的队首进程运行。○2在一个时间片用完时,计时器中断处理程序被激活;如果进程尚未运行完毕,调度程序就把它送到就绪队列的末尾,再调度就绪队列的队首进程运行。○3进程在运行过程中遇到事件需要阻塞,这时即把该进程的状态由运行改为阻塞并置入事件阻塞队列末尾,然后激活调度程序,调度就绪队列的队首进程运行。○4在进程的阻塞事件完成后,向系统发送阻塞完成的信息,系统在收到相关信息后,就把该进程从阻塞队列中删除并置入就绪队列末尾。

三、实验过程记录:

1、算法的思路

首先实现本算法需要用到PCB以及PCB队列两个主要数据结构,编写函数实现PCBQueue的增删以及输出,还要实现对PCB控制块赋值的代码。通过对文件的操作封装readFile方法,获取txt文件中的数据对PCBQueue初始化,根据要求格式化输出。最后根据时间片轮转调度算法对进程进行模拟操作,输出每次运行的结果。

2、主要数据结构

	PCB结构体
1.	typedef struct PCB
2.	 {
3.	     int id;                            /* 进程id */
4.	     string name;                    /* 进程标识符 */
5.	     int allTime;                       /* 进程共需要占用 CPU 时间 */
6.	     int needTime;                      /* 进程到完成还需要的时间 */
7.	     int cpuTime;                      /* 进程已经占用CPU的时间 */
8.	     int startBlock;                      /* 开始阻塞的时刻,-示不会发生阻塞*/
9.	     int blockTime;                      /* 阻塞消耗的总时间 */
10.	     string state;/* 进程的状态:就绪、阻塞、运行、完成*/
11.	     int blockT=//已经阻塞的时间
12.	     PCB *next;                /*链指针*/
13.	 } PCB;
PCB队列结构体
14.	 struct PCBQueue{
15.	     PCB *head=NULL;
16.	     PCB *end=NULL;
17.	 };
18.	 void addPCB(PCBQueue &q,PCB *next){
19.	     if(q.head==NULL){
20.	         q.head=q.end=next;
21.	         return;
22.	     }
23.	     next->next=NULL;
24.	     q.end->next=next;
25.	     q.end=next;
26.	 }
27.	 
28.	 PCB* deletePCBQueue(PCBQueue &q){
29.	     PCB *p=q.head;
30.	     if(q.head->next==NULL){
31.	         q.head=NULL;
32.	         q.end=NULL;
33.	     }else{
34.	         q.head=q.head->next;
35.	     }
36.	     p->next=NULL;
37.	     return p;
38.	 }
39.	 void PrintPCBQueue(PCBQueue &q){
40.	     if(q.head==NULL)
41.	         return;
42.	     PCB *p=q.head;
43.	     while(p!=q.end){
44.	         cout<<"id"<<p->id<<" -> ";
45.	         p=p->next;
46.	     }
47.	     cout<<"id"<<p->id;
48.	 }

主要数据结构为进程控制块PCB的结构体以及对他进行操作的函数

3、程序代码

1.	#include <iostream>
2.	#include <queue>
3.	#include <fstream>
4.	#define TIMESLICE 5
5.	using namespace std;
6.	
7.	typedef struct PCB
8.	{
9.	    int id;                            /* 进程id */
10.	    string name;                    /* 进程标识符 */
11.	    int allTime;                       /* 进程共需要占用 CPU 时间 */
12.	    int needTime;                      /* 进程到完成还需要的时间 */
13.	    int cpuTime;                      /* 进程已经占用CPU的时间 */
14.	    int startBlock;                      /* 开始阻塞的时刻,-1表示不会发生阻塞*/
15.	    int blockTime;                      /* 阻塞消耗的总时间 */
16.	    string state;/* 进程的状态:就绪、阻塞、运行、完成*/
17.	    int blockT=0;//已经阻塞的时间
18.	    PCB *next;                /*链指针*/
19.	} PCB;
20.	struct PCBQueue{
21.	    PCB *head=NULL;
22.	    PCB *end=NULL;
23.	};
24.	void addPCB(PCBQueue &q,PCB *next){
25.	    if(q.head==NULL){
26.	        q.head=q.end=next;
27.	        return;
28.	    }
29.	    next->next=NULL;
30.	    q.end->next=next;
31.	    q.end=next;
32.	}
33.	
34.	PCB* deletePCBQueue(PCBQueue &q){
35.	    PCB *p=q.head;
36.	    if(q.head->next==NULL){
37.	        q.head=NULL;
38.	        q.end=NULL;
39.	    }else{
40.	        q.head=q.head->next;
41.	    }
42.	    p->next=NULL;
43.	    return p;
44.	}
45.	void PrintPCBQueue(PCBQueue &q){
46.	    if(q.head==NULL)
47.	        return;
48.	    PCB *p=q.head;
49.	    while(p!=q.end){
50.	        cout<<"id"<<p->id<<" -> ";
51.	        p=p->next;
52.	    }
53.	    cout<<"id"<<p->id;
54.	}
55.	PCB initialize(int id,string name,int allTime,int needTime,int cpuTime,int startBlock,int blockTime,string state,struct PCB *next){
56.	    PCB p;
57.	    p.id=id;
58.	    p.name=name;
59.	    p.allTime=allTime;
60.	    p.needTime=needTime;
61.	    p.cpuTime=cpuTime;
62.	    p.startBlock=startBlock;
63.	    p.blockTime=blockTime;
64.	    p.state=state;
65.	    p.next=next;
66.	    p.blockT=0;
67.	    return p;
68.	}
69.	void readFile(PCB p[6]){
70.	    ifstream outfile("C:\\Users\\社会人\\Desktop\\操作系统\\data.txt");
71.	    int id;string name;int allTime;int needTime;int cpuTime;int startBlock;int blockTime;string state;
72.	    int time=0;
73.	    while(outfile>>id>>name>>allTime>>needTime>>cpuTime>>startBlock>>blockTime>>state){
74.	        p[time]=initialize(id,name,allTime,needTime,cpuTime,startBlock,blockTime,state,NULL);
75.	        time++;
76.	    }
77.	    outfile.close();
78.	}
79.	void printFirstPCB(PCB p[6],PCBQueue readPCB){
80.	    cout<<"程序开始:"<<endl;        /* 用整数表示的时间,开始时为0 */
81.	    cout<<"当前时间:"<<0<<endl;
82.	    cout<<"各个就绪进程的信息如下:"<<endl;
83.	    cout<<"就绪队列:";
84.	    PrintPCBQueue(readPCB);
85.	    cout<<endl;  /* 显示就绪队列所有的进程,假设系统开始有6个进程 */
86.	    cout<<"========================================================================"<<endl;
87.	    cout<<" id name allTime needTime cpuTime startBlock blockTime state"<<endl;
88.	    cout<<"------------------------------------------------------------------------"<<endl;
89.	    for(int i=0;i<6;i++){
90.	        printf("  %d\t %s\t\t\t%d\t\t%d\t\t\t%d\t\t%d\t\t\t%d\t\t%s\n",p[i].id,p[i].name.c_str(),p[i].allTime,p[i].needTime,p[i].cpuTime,p[i].startBlock,p[i].blockTime,p[i].state.c_str());
91.	    }
92.	    cout<<"------------------------------------------------------------------------"<<endl;
93.	}
94.	void printPCB(PCB p[6],int t,int m,PCBQueue readPCB,PCBQueue blockPCB,PCBQueue completPCB){
95.	    cout<<"第"<<t<<"次有程序状态变化:"<<endl;
96.	    cout<<"当前时间:"<<m<<endl;        /* 用整数表示的时间,开始时为0 */
97.	    cout<<"运行状态程序:id, name, allTime, needTime, cpuTime, startBlock, blockTime, state"<<endl;
98.	    cout<<"就绪队列:";
99.	    PrintPCBQueue(readPCB);/* 显示就绪队列所有的进程 */
100.	    cout<<endl;
101.	    cout<<"阻塞队列:";
102.	    PrintPCBQueue(blockPCB);
103.	    cout<<endl;
104.	    /* 显示阻塞队列所有的进程 */
105.	    cout<<"完成队列:";
106.	    PrintPCBQueue(completPCB);/* 显示完成队列所有的进程 */
107.	    cout<<endl;
108.	    cout<<"========================================================================"<<endl;
109.	    cout<<" id name allTime needTime cpuTime startBlock blockTime state"<<endl;
110.	    cout<<"------------------------------------------------------------------------"<<endl;
111.	    for(int i=0;i<6;i++){
112.	        printf("  %d\t %s\t\t\t%d\t\t%d\t\t\t%d\t\t%d\t\t\t%d\t\t%s\n",p[i].id,p[i].name.c_str(),p[i].allTime,p[i].needTime,p[i].cpuTime,p[i].startBlock,p[i].blockTime,p[i].state.c_str());
113.	    }
114.	    cout<<"------------------------------------------------------------------------"<<endl;
115.	}
116.	void SchedulingAlgorithm(PCB p[6],int m,int t,PCBQueue readPCB,PCBQueue blockPCB,PCBQueue completPCB){
117.	    PCB *readp=NULL;
118.	    bool flag;
119.	    int readTime;
120.	    while(readPCB.head!=NULL||blockPCB.head!=NULL){
121.	        if(readPCB.head==NULL){
122.	            PCB *blockP=deletePCBQueue(blockPCB);
123.	            m+=blockP->blockTime-blockP->blockT;
124.	            blockP->blockT=0;
125.	            blockP->state="READY";
126.	            addPCB(readPCB,blockP);
127.	            printPCB(p,t++,m,readPCB,blockPCB,completPCB);
128.	        }
129.	        if(readPCB.head!=NULL){
130.	            readp=deletePCBQueue(readPCB);
131.	            readp->state="RUNNING";
132.	            printPCB(p,t++,m,readPCB,blockPCB,completPCB);
133.	            flag=false;
134.	            readTime=0;
135.	            if(readp->startBlock!=-1){
136.	                if(readp->startBlock<=TIMESLICE){
137.	                    if(readp->needTime<=readp->startBlock){//运行完
138.	                        readTime+=readp->needTime;
139.	                        m+=readp->needTime;
140.	                        readp->cpuTime+=readp->needTime;
141.	                        readp->needTime=0;
142.	                        readp->state="FINISHED";
143.	                        addPCB(completPCB,readp);
144.	                        printPCB(p,t++,m,readPCB,blockPCB,completPCB);
145.	                    }else{//阻塞
146.	                        readTime+=readp->startBlock;
147.	                        m+=readp->startBlock;
148.	                        readp->cpuTime+=readp->startBlock;
149.	                        readp->needTime-=readp->startBlock;
150.	                        readp->state="BLOCKED";
151.	                        readp->startBlock=-1;
152.	                    }
153.	                }else
154.	                    flag=true;
155.	            }else
156.	                flag=true;
157.	            if(flag){//正常运行
158.	                if(readp->needTime<=TIMESLICE){//运行完
159.	                    readTime+=readp->needTime;
160.	                    m+=readp->needTime;
161.	                    readp->cpuTime+=readp->needTime;
162.	                    readp->needTime=0;
163.	                    readp->state="FINISHED";
164.	                    addPCB(completPCB,readp);
165.	                    printPCB(p,t++,m,readPCB,blockPCB,completPCB);
166.	                }else{//没有运行完
167.	                    readTime+=TIMESLICE;
168.	                    readp->cpuTime+=TIMESLICE;
169.	                    readp->needTime-=TIMESLICE;
170.	                    readp->state="READY";
171.	                    m+=TIMESLICE;
172.	                    addPCB(readPCB,readp);
173.	                    printPCB(p,t++,m,readPCB,blockPCB,completPCB);
174.	                }
175.	            }
176.	        }
177.	        while(blockPCB.head!=NULL&&readp!=NULL){
178.	            PCB *blockP=deletePCBQueue(blockPCB);
179.	            if(readTime==0)
180.	                break;
181.	            if(blockP->blockTime-blockP->blockT>readTime){//时间用完
182.	                readTime=0;
183.	                blockP->blockT+=readTime;
184.	                break;
185.	            }else{//阻塞结束
186.	                readTime-=(blockP->blockTime-blockP->blockT);
187.	                blockP->blockT=0;
188.	                blockP->state="READY";
189.	                addPCB(readPCB,blockP);
190.	                printPCB(p,t++,m,readPCB,blockPCB,completPCB);
191.	            }
192.	        }
193.	        if(readp->state=="BLOCKED"){
194.	            addPCB(blockPCB,readp);
195.	            printPCB(p,t++,m,readPCB,blockPCB,completPCB);
196.	        }
197.	    }
198.	}
199.	int main(){
200.	    PCB p[6],*readp;
201.	    readFile(p);
202.	    int m=0,t=1;//时间和次数
203.	    PCBQueue readPCB,blockPCB,completPCB;//就绪 阻塞 完成
204.	    for(int i=0;i<6;i++){
205.	        addPCB(readPCB,&p[i]);
206.	    }
207.	    printFirstPCB(p,readPCB);
208.	    SchedulingAlgorithm(p,m,t,readPCB,blockPCB,completPCB);
209.	}

运行效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐