【操作系统实验】模拟单处理器系统的进程调度

详解‘带时间片的先来先服务’进程调度算法
本文提供了一个简单的‘带时间片的先来先服务’进程调度算法实现,包括进程控制块初始化、创建进程、进程调度函数及详细注释代码。适合操作系统原理学习者及编程爱好者。

        操作系统本来就是一门令人十分郁闷的课,学生想学好,但很难看懂,而老师又不好讲课,但看来学校的领导显然还没有意识到这点,还居然要咱们把进程的调度算法给写出来(真的很想给老师们一个good……)!虽然是一个比较简单的“带时间片的先来先服务”调度算法(而且是一个阉割版本),但对于编程能力不强、对操作系统原理不熟悉的同学仔来讲,仍然是一次华丽的绝杀,血雨腥风……

        本来打算从网上随便copy一份过来应酬一下的,不过发现有些确实十分垃圾(至少我找到的那一份就是),完全看不出进程调度过程的执行就直接输出一些不知名的东西出来。看来,上天还是要我自己把残局收拾。最后,经过一整天的努力(……此部分省略了五千字……),终于写了一个出来了,如果不在此keep一份,恐怕对不起自己的辛勤付出吧(******不过顺顺哥应该不会也看到这个空间然后以为我的代码是抄袭的吧,有点担心哟,所以如果各位大哥大姐想要转载代码的话,请标明出处为http://hi.baidu.com/waltertan/blog/item/fec1ad802b8063df9023d9e4.html,谢谢******)?呵呵……星期五一早就要把全班每个人的实验册和报告交给顺顺哥了……又要做搬运工啦,哈哈。

代码如下:

#include<stdio.h>
#include<stdlib.h>

#define RUNNING 1//用RUNNING 表示进程处于运行态
#define WAIT 2//用wait表示进程处于就绪态
#define FINISH 3//用FINISH表示进程已经执行完毕
#define TIME_PIECE 5//用TIME_PIECE表示时间片大小
#define MAX_PROCESS_NUM 10//假定系统允许进程个数为10

int AX,BX,CX,DX,PC,PSW,TIME;//模拟寄存器
int run;//定义指向正在运行进程的进程控制块的指针
int pfree;//定义指向空闲进程控制块队列的指针

struct{
int head;
int tail;
}ready;//定义指向就绪队列的头指针head和尾指针tail

struct{
int name;//进程标识符
int status;//进程状态
int ax, bx, cx,dx;//进程现场信息,通用寄存器内容
int pc;//进程现场信息,程序计数器内容
int psw;//进程现场信息,程序状态字寄存器内容
int time;//进程每次申请的时间片大小

int totalTime;//执行进程需要的总时间
int remainingTime;//进程剩余的执行时间

int next;//下一个进程控制块的位置
}pcbarea[MAX_PROCESS_NUM];//定义模拟进程控制块区域的数组


//进程控制块初始化
void Init(){
int i;
run=ready.head=ready.tail=-1;//运行指针、就绪指针清空
pfree=0;//空闲指针指向第一个进程
for(i=0;i<MAX_PROCESS_NUM-1;++i)
   pcbarea[i].next=i+1;
pcbarea[MAX_PROCESS_NUM-1].next=-1;
}


//创建进程
void Create(int process_name,int ax,int bx,int cx,int dx,int pc,int psw,int totalTime){
int i;
if(pfree==-1){
   //空闲进程控制块队列为空
   printf("无空闲进程控制块,进程创建失败\n");
   return;
}
i=pfree;//取空闲进程控制块队列的第一个
pfree=pcbarea[pfree].next;//pfree后移
//填写该进程控制块内容
pcbarea[i].name=process_name;
pcbarea[i].status=WAIT;
pcbarea[i].ax=ax;
pcbarea[i].bx=bx;
pcbarea[i].cx=cx;
pcbarea[i].dx=dx;
pcbarea[i].pc=pc;
pcbarea[i].psw=psw;
pcbarea[i].time=TIME_PIECE;
pcbarea[i].totalTime=totalTime;
pcbarea[i].remainingTime=totalTime;
if(ready.head!=-1){
   //就绪队列不空时,置入就绪队列
   pcbarea[ready.tail].next=i;
   ready.tail=i;
   pcbarea[ready.tail].next=-1;
}
else{
   //就绪队列空时,置入就绪队列
   ready.head=i;
   ready.tail=i;
   pcbarea[ready.tail].next=-1;
}
printf("\n");
}


//进程调度函数
void Sheduling(){
getchar();
if(ready.head==-1){
   //空闲进程控制块队列为空,退出
   printf("进程调度完毕!\n\n\n");
   return;
}
run=ready.head;//就绪队列头指针赋给run,即让就绪队列的队头运行
ready.head=pcbarea[ready.head].next;//就绪队列头指针后移
if(ready.head==-1)
   ready.tail=-1;//就绪队列为空,修正尾指针ready.tail

pcbarea[run].status=RUNNING;//修改进程控制块状态
//恢复该进程现场信息
AX=pcbarea[run].ax;
BX=pcbarea[run].bx;
CX=pcbarea[run].cx;
DX=pcbarea[run].dx;
PC=pcbarea[run].pc;
PSW=pcbarea[run].psw;
TIME=pcbarea[run].time;//设置相对时钟寄存器的时间片

//打印进程以及系统的状态信息
printf("\n进程编号:%d\n",pcbarea[run].name);
printf("进程状态:运行\n");
printf("寄存器内容:\n");
printf("AX: %d\n",AX);
printf("BX: %d\n",BX);
printf("CX: %d\n",CX);
printf("DX: %d\n",DX);
printf("PC: %d\n",PC);
printf("PSW: %d\n",PSW);
printf("TIME:%d\n\n",TIME);
printf("\n**时间片用完**\n");

AX=BX=CX=DX=PC=PSW=TIME=0;//时间片用完立即归还CPU资源

//若进程执行完毕,则回收进程控制块
if(pcbarea[run].remainingTime<=TIME_PIECE){
   getchar();
   pcbarea[run].remainingTime=0;
   pcbarea[run].status=FINISH;
   ready.head=pcbarea[run].next;
    
   //打印进程以及系统的状态信息
   printf("\n进程编号:%d\n",pcbarea[run].name);
   printf("进程状态:完成\n");
   printf("寄存器内容:\n");
   printf("AX: %d\n",AX);
   printf("BX: %d\n",BX);
   printf("CX: %d\n",CX);
   printf("DX: %d\n",DX);
   printf("PC: %d\n",PC);
   printf("PSW: %d\n",PSW);
   printf("TIME:%d\n\n",TIME);

   //将该进程控制块置入空闲队列
   if(pfree==-1){
    pfree=run;
    pcbarea[pfree].next=-1;
   }
   else{
    pcbarea[pfree].next=run;
    pfree=run;
    pcbarea[run].next=-1;
   }
}

//若进程还没执行完毕,则将其置入就绪队列,等待下次的时间片到来
else{
   getchar();
   pcbarea[run].remainingTime-=TIME_PIECE;
   pcbarea[run].status=WAIT;

   //将进程置入就绪队列中
   if(ready.tail!=-1)
    pcbarea[ready.tail].next=run;
   else
    ready.head=ready.tail=run;
   pcbarea[run].next=-1;
   ready.tail=run;

   //打印进程以及系统的状态信息
   printf("\n进程编号:%d\n",pcbarea[run].name);
   printf("进程状态:等待\n");
   printf("寄存器内容:\n");
   printf("AX: %d\n",AX);
   printf("BX: %d\n",BX);
   printf("CX: %d\n",CX);
   printf("DX: %d\n",DX);
   printf("PC: %d\n",PC);
   printf("PSW: %d\n",PSW);
   printf("TIME:%d\n\n",TIME);
}
Sheduling();//如果还有进程没有执行完毕,则继续递归调度
}


void main(){
int process_name,ax,bx,cx,dx,pc,psw,totalTime;
int i;
char quit;//用于选择退出进程模拟系统

do {
   i=MAX_PROCESS_NUM;
   printf("==========================模拟单处理器系统的进程调度==========================\n\n\n");
   Init();
   printf("**创建进程,输入负数可结束创建**\n\n");
   printf("输入一个进程的编号(现在还可以创建%d个进程):",i);
   scanf("%d",&process_name);
   while(process_name>0){
    printf("请输入该进程中ax、bx、cx、dx、pc、psw的初始现场信息:");
    scanf("%d%d%d%d%d%d",&ax,&bx,&cx,&dx,&pc,&psw);
    printf("请输入该进程运行所需的总时间:");
    scanf("%d",&totalTime);
    Create(process_name,ax,bx,cx,dx,pc,psw,totalTime);
    if(i>0)
     --i;
    printf("输入一个进程的编号(现在还可以创建%d个进程):",i);
    scanf("%d",&process_name);
   }
   system("cls");
   printf("请按回车开始调度……");
   getchar();
   Sheduling();
  
   printf("退出请按0,重新测试请按任意键:");
   quit=getchar();
   system("cls");
} while(quit!='0');

printf("\n\n");
}

编写一个单处理机下的进程调度程序,模拟操作系统进程调度。 要求: 1.能够创建指定数量的进程,每个进程由一个进程控制块表示。 2.实现先来先服务调度算法进程到达时间可由进程创建时间表示。 3.实现短作业优先调度算法:可指定进程要求的运行时间。(说明:对不可剥夺的短作业优先算法,当作业运行时间相等时,优先调度进程号小的进程执行;对可剥夺式的短作业优先算法,即选最短剩余时间的进程进行运行,在剩余时间相同的情况下,选择到达时间早的进程进行运行) 4. 实现时间片轮转调度算法:可指定生成时间片大小。(说明:新进程到来时插入到就绪队列的队尾,当进程P运行完一个时间片时,若同时有进程Q到达,则先在就绪队列队尾插入新到达的进程Q,之后再插入进程P) 5.实现动态优先级调度算法:可指定进程的初始优先级(优先级与优先数成反比,优先级最高为0),优先级改变遵循下列原则:进程在就绪队列中每停留一个时间片,优先级加1,进程每运行一个时间片,优先级减3。(说明:本算法在优先级相同的情况下,选择到达时间早的进程进行运行) 测试用例格式如下: 输入:调度算法    进程号/到达时间/运行时间/优先级/时间片 输出:调度顺序/进程号/开始运行时间/结束运行时间/优先级 其中调度算法选项为:1----先来先服务,2----短作业优先,3----最短剩余时间优先,4----时间片轮转,5----动态优先级
实验单处理器系统进程调度 1.实验目的 加深对进程概念的理解,明确进程和程序的区别; 深入了解系统如何组织进程、创建进程; 进一步认识如何实现处理器调度。 2.实验预备知识 进程的概念; 进程的组织方式; 进程的创建; 进程调度。 3.实验内容 编写程序完成单处理机系统中的进程调度,要求采用时间片轮转调度算法实验具体包括:首先确定进程控制块的内容,进程控制块的组成方式;然后完成进程创建原语和进程调度原语;最后编写主函数对所作工作进程测试。 4.提示与讲解 这个实验主要要考虑三个问题:如何组织进程、如何创建进程和如何实现处理器调度。 考虑如何组织进程,首先就要设定进程控制块的内容。进程控制块PCB记录各个进程执行时的情况。不同的操作系统进程控制块记录的信息内容不一样。操作系统功能越强,软件也越庞大,进程控制块记录的内容也就越多。这里的实验只使用了必不可少的信息。一般操作系统中,无论进程控制块中信息量多少,信息都可以大致分为以下四类: ① 标识信息 每个进程都要有一个惟一的标识符,用来标识进程的存在和区别于其他进程。这个标识符是必不可少的,可以用符号或编号实现,它必须是操作系统分配的。在后面给出的参考程序中,采用编号方式,也就是为每个进程依次分配一个不相同的正整数。
实验内容: 编写一个单处理机下的进程调度程序,模拟操作系统进程调度。 要求: 能够创建指定数量的进程,每个进程由一个进程控制块表示。 实现先来先服务调度算法进程到达时间可由进程创建时间表示。 实现短作业优先调度算法:可指定进程要求的运行时间。(说明:对不可剥夺的短作业优先算法,当作业运行时间相等时,优先调度进程号小的进程执行;对可剥夺式的短作业优先算法,即选最短剩余时间的进程进行运行,在剩余时间相同的情况下,选择到达时间早的进程进行运行) 实现时间片轮转调度算法:可指定生成时间片大小。(说明:新进程到来时插入到就绪队列的队尾,当进程P运行完一个时间片时,若同时有进程Q到达,则先在就绪队列队尾插入新到达的进程Q,之后再插入进程P) 实现动态优先级调度算法:可指定进程的初始优先级(优先级与优先数成反比,优先级最高为0),优先级改变遵循下列原则:进程在就绪队列中每停留一个时间片,优先级加1,进程每运行一个时间片,优先级减3。(说明:本算法在优先级相同的情况下,选择到达时间早的进程进行运行) 测试用例格式如下: 输入:调度算法    进程号/到达时间/运行时间/优先级/时间片 输出:调度顺序/进程号/开始运行时间/结束运行时间/优先级 其中调度算法选项为:1----先来先服务,2----短作业优先,3----最短剩余时间优先,4----时间片轮转,5----动态优先级
实现了如下四种调度算法模拟: (1)时间片轮转调度 (2)优先数调度 (3)最短进程优先 (4)最短剩余时间优先 模拟过程使用了JProgressBar作为进程状态条,更为直观地观察到每个进程的执行状态。 程序用户说明: 1、在上图标号1处输入要创建随机进程的个数,仅可输入正数,非正数会有相关提示。然后点击标号2处的“创建进程”按钮,随进创建的进程显示在程序界面的中央窗口,如标号3所示。 2、创建好随机进程后,在标号4的单选框选择将要模拟执行的调度算法,然后点击标号5处的“开始模拟”,程序开始执行。标号3的列表会显示相应的调度变化。 3、模拟过程中,可以继续添加新的进程,操作同上。 4、 一个算法模拟执行完毕之后,可以点击标号6的“复位”按钮,可以重置列表的内容为程序模拟运行前的内容。复位成功后,可以继续选择其他调度算法进行模拟。 5、标号7显示为程序模拟过程中的时间,从1秒开始累计。 6、点击标号8的“清空”按钮,可以清空类别的进程,以便程序的下次执行。 题目要求: 题目四 单处理器系统进程调度 一 、 课 程 设 计 目 的 1. 加深对进程概念的理解, 明确进程和程序的区别。 2. 深入了解系统如何组织进程、 创建进程。 3. 进一步认识如何实现处理器调度。 二 、 课 程 设 计 内 容 编写程序完成单处理器系统中的进程调度, 要求实现时间片轮转、 优先数、 最短进程优 先和最短剩余时间优先四种调度算法实验具体包括: 首先确定进程控制块的内容, 进程控 制块的组成方式; 然后完成进程创建原语和进程调度原语; 最后编写主函数对所作工作进行 测试。 模拟程序只对你所设置的“ 虚拟 PCB” 进行相应的调度模拟操作, 即每发生“ 调度” 时, 显示出当前运行进程的“ 进程标识符”、“ 优先数”、“ 剩余运行时间” 等, 而不需要对系 统中真正的 PCB 等数据进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值