问题描述:
多道程序设计中,经常是若干个进程同时处于就绪状态,必须依照某种策略来决定那个进程优先占有处理机。因而引起进程调度。本实验模拟在单处理机情况下的处理机调度问题,加深对进程调度的理解。
调度算法:
优先权法–动态优先权
轮转法
程序流程图:
编程思路:
首先定义进程Thread
进程Thread有以下几个属性:
name(进程名) 这里就简单的用数字表时进程名
runTime(进程运行时间)
priority(进程的优先级) 数字表示进程的优先等级,数值越大则优先等级越高
进程所采用的存贮方式就是定义的Thread类型的数组
下面我就主要描述一下两个算法是如何实现的。
优先权算法
实验要求的算法是动态优先权,即当一个进程占用CPU一段时间(本实验是一个时间片)之后,其优先等级要下降(本实验为3)。
优先权方法整体为一个while循环,循环终止的条件是所有的进程都执行完毕即所有Thread的runTime都为0。调度每次开始时都要对所有未结束的进程进行一次遍历以寻找优先等级最高的进程,这里我简单的用一个方法实现的,如果进程数目较大的话还是建议用一个 优先队列来实现。找到优先等级最高的进程之后就可以将其调入处理机,将其runTime–,priority-3。这还不是一次调度的完成,此时应考虑的是此进程是否已经执行完毕了即其runTime是否为0,若为0则进行标记并将其优先等级置为–Integer.MAX_VALUE。这时候一次调度就完成了,用一个循环重复上述步骤直至所有进程都执行完毕。
测试用例:
轮转法
轮转法首先需要明确的是CPU的时间片数量size,这里我设置为4,也可以根据要求进行动态的设置。
轮转法是一次调入size个进程,即将size个进程(这里按照进程的顺序进行选择,即若有有5个进程(runTime>1)则第一次为 1 2 3 4 第二次为 5 1 2 3 )的runTime–,然后判断其是否执行完毕,若执行完毕则进行标记,其将不再参与下一次的调度。但是这里要考虑到初始时或者执行一段时间之后为执行完毕进程数目小于size的情况(我这里是规定了即使CPU有多余的资源,一次进程也只能使用一个时间片,但是将多余的资源进行再分配也是合理的,实验没有明确指名)。重复上述操作直至所有进程都执行完毕。
测试用例
PS:循环结束的判定
我定义了一个数组,数组中的每个元素对应一个进程。初始时数组元素都为1
,当其对应的进程执行完毕即runTime为0时将数值置0。每次循环开始时将会计算该数组的所有元素之和是否为0,若为0则终止循环,否则将继续执行。
实验代码(java)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
Thread course[]=new Thread[8];
System.out.println("\t请输入进程数目(5~8个)");
int N=scanner.nextInt();
for(int i=0;i<N;i++) //节点初始化
{
course[i]=new Thread();
}
for(int i=0;i<N;i++)
{
//System.out.println("请输入"+(i+1)+"个进程的进程名");
course[i].name=i+1;
//System.out.println("请输入"+(i+1)+"个进程的等待时间");
course[i].runTime=(int)(Math.random()*10+1);
//System.out.println("请输入"+(i+1)+"个进程的执行时间");
course[i].priority=(int)(Math.random()*20+1);
}
System.out.println("\t节点生成完成\n\t节点信息为");
Print(course,N);
System.out.println("\t请选择所采用的调度算法");
System.out.println("\t1\t优先权法\t2\t轮转法");
int choose=scanner.nextInt();
while(choose!=1&&choose!=2)
{
System.out.println("\t请输入有效选项");
choose=scanner.nextInt();
}
switch (choose) {
case 1:
P(course,N);
break;
case 2:
L(course,N);
default:
break;
}
}
public static void Print(Thread course[],int N) {
System.out.println("\t进程名\t进程所需运行时间 \t进程优先级 ");
for(int i=0;i<N;i++)
{
System.out.println("\t"+course[i].name+"\t"+course[i].runTime+"\t\t"+course[i].priority);
}
}
public static void Prints(Thread course[],int N) {
System.out.println("\t进程名\t 进程所需运行时间\t");
for(int i=0;i<N;i++)
{
if(course[i].runTime>0)
System.out.println("\t"+course[i].name+"\t"+course[i].runTime);
}
}
public static void P(Thread course[],int N)
{
int flag[]=new int [N]; //定义一个标记
for(int i=0;i<N;i++) //标记初始化
{
flag[i]=1;
}
int m=1;
while(true)
{
int sum=0;
for(int i=0;i<N;i++)
{
sum+=flag[i];
}
if(sum==0) //即所有进程都完成
{
System.out.println("\t所有进程执行完毕");
break;
}
System.out.println("-------------执行第"+m+"次调度------------------");
m++;
int flage=seachMax(course, N,flag);
System.out.println("\t本次执行的程序为:"+course[flage].name+"号进程");
course[flage].runTime--;
course[flage].priority=course[flage].priority-3;
if(course[flage].runTime==0)
{
flag[flage]=0;
course[flage].priority=-Integer.MAX_VALUE;
}
System.out.println("\t调度后的进程参数为:");
Print(course, N);
if(course[flage].runTime==0)
System.out.println("进程"+course[flage].name+"结束");
}
}
public static void L(Thread course[],int N)
{
int M=N;
System.out.println("采用的进程调度方法为时间片轮转法");
System.out.println("时间片设定为4");
int flag[]=new int [N]; //定义一个标记
for(int i=0;i<N;i++) //标记初始化
{
flag[i]=1;
}
int m=1;
int count=0;
while(true)
{
int sum=0;
for(int i=0;i<N;i++)
{
sum+=flag[i];
}
if(sum==0) //即所有进程都完成
{
System.out.println("------所有进程执行完毕-------");
break;
}
System.out.println("-------------执行第"+m+"次调度------------------");
m++;
System.out.println("\t调度后的进程参数为:");
if(M<=4)
{
for(int i=0;i<N;i++)
{
if(course[i].runTime!=0)
{
course[i].runTime--;
if(course[i].runTime==0)
{
flag[i]=0;
System.out.println("进程"+course[i].name+"结束");
}
}
}
Prints(course, N);
}else if(M>4){
for(int i=0;i<4;i++)
{
course[count].runTime--;
if(course[count].runTime==0)
{
flag[count]=0;
System.out.println("进程"+course[count].name+"结束");
M--;
}
count++;
if(count==N)
count=0;
}
Prints(course, N);
}
}
}
public static int seachMax(Thread course[],int N,int flag[]) //寻找优先权最大的进程号
{
int flage=Integer.MAX_VALUE;
int max=-Integer.MAX_VALUE;
for(int i=0;i<N;i++)
{
if(course[i].priority>max&&flag[i]==1)
{
max=course[i].priority;
flage=i;
}
}
return flage;
}
static class Thread
{
int name;
int runTime;
int priority;
public void Thread()
{
}
}
}