在多道程序环境下,内存中着多个进程,进程数目往往多于处理机数目,这时候我们就要针对该问题设计某种算法,动态地将处理机分配给处于就绪状态的一个进程。进程的调度算法有很多,例如先来先服务调度算法(FCFS),短作业优先算法(SJF),时间片轮转算法(RR)和优先级算法,这里我将通过代码的方式主要介绍轮转调度算法(RR)和动态优先级调度算法.
首先介绍下轮转调度算法:
A.轮转法的基本原理:
在轮转法(RR)法中,系统将所有的就绪进程按FCFS策略排成一个就绪队列。系统可设置每隔一定时间(如30ms)便产生一次中断,去激活进程调度程序进行调度,把CPU分配给队首进程,并令其执行一个时间片。当它运行完毕后,又把处理机分配给就绪队列中新的队首进程,也让其执行一个时间片片。这样,就可以保证就绪队列中的所有进程在确定的时间段内,都能获得一个时间片的处理机时间。
B.进程切换时机:
在轮转调度算法中,应在何时进行进程的切换,可分成两种情况:1.若一个时间片尚未用完,正在运行的进程便已经完成,就立即激活调度程序,将它从就绪队列中删除,在调度就绪队列中队首的进程运行,并启动一个新的时间片。2.在一个时间片用完时,计时器中断处理程序被激活。如果进程尚未运行完毕,调度程序将把它送往就绪队列的末尾。
C.时间片大小的确定:
在轮转算法中,时间片的大小对系统性能有着很大的影响。若选择很小的时间内片,将有利于短作业,因为它能在该时间片内完成。但时间片小,意味着会频繁地执行进程调度和进程上下文的切换,这无疑会增加系统的开销。反之,若事件片选择的太长,且为使每个进程都能在一个时间片内完成,轮转算法便退化为FCFS算法,无法满足短作业和交互式用户的需求。一个较为可取的时间片大小是略大于一次典型的交互所需要的时间,使大多数交互式进程能在一个时间片内完成,从而可以获得很小的响应时间。
D.算法流程图:
E.实现代码:
class PCBRR{
public int id;
public int everyTimeCount;
public int alreadyCpuTime;
public int stillNeedCpuTime;
public PCBRR(int id, int everyTimeCount, int alreadyCpuTime, int stillNeedCpuTime) {
super();
this.id = id;
this.everyTimeCount = everyTimeCount;
this.alreadyCpuTime = alreadyCpuTime;
this.stillNeedCpuTime = stillNeedCpuTime;
}
@Override
public String toString() {
return "进程号:" + this.id + " 已占有的CPU时间:" + this.alreadyCpuTime + " 还需的CPU时间:"
+ this.stillNeedCpuTime+" 每次轮转的时间片数:"+this.everyTimeCount;
}
}
private static void RoundRobin() {
LinkedList pcbs = new LinkedList();
System.out.println("请输入进程数目:");
int num = scanner.nextInt();
System.out.println("系统为这" + num + "个进程随机分配优先级数和运行所需的CPU数.以下是进程的详细情况:");
for (int i = 0; i < num; i++) {
//产生n个进程(id号,每次轮转的时间片数,已占用的CPU时间片数,仍需要的时间片数)
pcbs.addLast(new PCBRR(i,random.nextInt(5) + 1, 0, random.nextInt(30) + 1));
}
Iterator iterator = pcbs.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println();System.out.println();
System.out.println("下面开始进行轮转法进程调度算法---------------");
LinkedList donePCB = new LinkedList();
int current = 1;
while(pcbs.size()>0)
{
System.out.println("当前正在执行第" + (current++) + "次时间片");
PCBRR pcbrr=pcbs.removeFirst();
System.out.println("将要执行的进程为 ----"+pcbrr);
pcbrr.alreadyCpuTime++;
pcbrr.stillNeedCpuTime--;
if(pcbrr.stillNeedCpuTime<=0) //进程总体运行结束
{
donePCB.addLast(pcbrr.id);
}
else if(pcbrr.alreadyCpuTime>=pcbrr.everyTimeCount)
{ //进程已经运行完其所分配的每次轮转时间片,将其放在轮转队尾
pcbrr.alreadyCpuTime=0;
pcbs.addLast(pcbrr);
}
//进程位运行完其所分配的每次轮转时间片,下面仍将继续运行该进程
else {
pcbs.addFirst(pcbrr);
}
System.out.println("执行完这个时间片后系统轮转队列中的所有进程的情况如下:");
if(pcbs.size()>0)
{
Iterator temp = pcbs.iterator();
while (temp.hasNext()) {
System.out.println(temp.next());
}
}
else
System.out.println("空");
System.out.println("已经完成的进程有:(用进程号表示)");
Iterator itera = donePCB.iterator();
if (!itera.hasNext()) {
System.out.println("无");
System.out.println();System.out.println();
System.out.println();System.out.println();
continue;
}
while (itera.hasNext()) {
System.out.print(itera.next()+" ");
}
System.out.println();System.out.println();
System.out.println();System.out.println();
}
System.out.println("轮转法进程调度算法结束---------------");
}
A.基本原理;
动态优先级调度算法是指在创建进程之初,先赋予其一个优先级,然后其值随着进程的推进或等待时间的增加而改变,以便获得更好的调度性能。例如,可以规定在就绪队列中的进程随其等待的时间的正常,使其优先级相应提高。若所有的进程都具有相同的优先级初值,则最先进入就绪队列的进程会因为其优先级变得最高,而优先获得处理机,这相当于FCFS算法。若所有的就绪进程具有各不相同的优先级初值,那么对于优先级初值低的进程,在等待了足够的时间后,也可以获得处理机。
B.算法流程图:
C.实现代码:
class PCBPM implements Comparable {
public int id;
public int pority;
public int cputime;
public PCBPM(int id, int pority, int cputime) {
super();
this.id = id;
this.pority = pority;
this.cputime = cputime;
}
@Override
public int compareTo(Object obj) {
PCBPM pcb = (PCBPM) obj;
if (pcb.pority >= this.pority)
return 1;
return -1;
}
@Override
public String toString() {
return "进程号:" + this.id + " 优先级:" + this.pority + " 所需的CPU时间:" + this.cputime;
}
}
private static void PriorityMethod() {
TreeSet pcbs = new TreeSet();
System.out.println("请输入进程数目:");
int num = scanner.nextInt();
System.out.println("系统为这" + num + "个进程随机分配优先级数和运行所需的CPU数.以下是进程的详细情况:");
for (int i = 0; i < num; i++) {
pcbs.add(new PCBPM(i, random.nextInt(60) + 1, random.nextInt(20) + 1));
}
Iterator iterator = pcbs.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println();System.out.println();
System.out.println("下面开始进行优先权进程调度算法---------------");
int current = 1;
LinkedList donePCB = new LinkedList();
while (pcbs.size() > 0) {
System.out.println("当前正在执行第" + (current++) + "次时间片");
PCBPM pcb = pcbs.pollFirst();
System.out.println("将要执行的进程为 ----" + pcb);
pcb.cputime--;
pcb.pority -= 3;
if (pcb.cputime <= 0)
donePCB.addLast(pcb.id);
else
pcbs.add(pcb);
System.out.println("执行完这个时间片后系统优先进程队列中的所有进程的情况如下:");
if (pcbs.size() > 0) {
Iterator temp = pcbs.iterator();
while (temp.hasNext()) {
System.out.println(temp.next());}}
else
System.out.println("空");
System.out.println("已经完成的进程有:(用进程号表示)");
Iterator itera = donePCB.iterator();
if (!itera.hasNext()) {
System.out.println("无");
System.out.println();System.out.println();
System.out.println();System.out.println();
continue;
}
while (itera.hasNext()) {
System.out.print(itera.next()+" ");
}
System.out.println();System.out.println();
System.out.println();System.out.println();
}
System.out.println("优先权进程调度算法结束
---------------");}
接下来是一些整合工作,我按照以下的流程方式将两种调度算法进行整合:
程序入口和相关静态对象的代码如下:
public static Scanner scanner = new Scanner(System.in);
public static Random random = new Random();
public static void main(String[] args) {
System.out.println("请选择进程调度的方法:");
System.out.println("1).优先权法 2).轮转法");
int choice = scanner.nextInt();
if (choice == 1)
PriorityMethod();
else
RoundRobin();
}
实验结果截图:
1).对于轮转调度算法:
。。。。。。。(由于截图过多,这里仅显示开头和结尾数据)2).对于动态优先级调度算法:
。。。。。。。(由于截图过多,这里仅显示开头和结尾数据)
PS:自发表了第一篇的银行家算法的博文,慢慢有了阅读量,小小的成就感爆棚,之后就顺手写下操作系统中比较重要的两种进程调度算法,动手写代码,对算法的理解肯定是有帮助的。最后,还是那句话,博客小白还望各位大佬不吝赐教~