一、進程調度
無論是在批處理還是分時系統中,用戶進程數一般都多於處理機數、這將導致它們互相爭奪處理機。另外,系統進程也同樣需要使用處理機。這就要求進程調度程序按一定的策略,動態地把處理機分配給處於就緒隊列中的某一個進程,以使之執行。進程調度屬於處理機調度。
處理機調度分爲三個層次:
package controlblock;
/**
* 進程控制塊
*
* @author wz
*
* @date 2015年11月10日
*/
public class PCB {
private int pid;
private double priority;
private int arriveTime;
private int needTime;
public PCB(int pid,int arriveTime,int needTime){
this.pid = pid;
this.arriveTime = arriveTime;
this.needTime = needTime;
}
public PCB(int pid, double priority, int arriveTime, int needTime) {
super();
this.pid = pid;
this.priority = priority;
this.arriveTime = arriveTime;
this.needTime = needTime;
}
public int getPid() {
return pid;
}
public double getPriority() {
return priority;
}
public void setPriority(double priority) {
this.priority = priority;
}
public int getArriveTime() {
return arriveTime;
}
public int getNeedTime() {
return needTime;
}
public void setNeedTime(int needTime) {
this.needTime = needTime;
}
}
先來先服務(FCFS)調度算法是一種最簡單的調度算法,該算法既可用於作業調度,也可用於進程調度。當在作業調度中採用該算法時,每次調度都是從後備作業隊列中選擇一個或多個最先進入該隊列的作業,將它們調入內存,爲它們分配資源、創建進程,然後放入就緒隊列。在進程調度中採用FCFS算法時,則每次調度是從就緒隊列中選擇一個最先進入該隊列的進程,爲之分配處理機,使之投入運行。該進程一直運行到完成或發生某事件而阻塞後才放棄處理機。
模擬算法如下:
package process.schedule;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import controlblock.PCB;
/**
* 先到先服務進程調度
*
* @author wz
*
* @date 2015年11月10日
*/
public class FCFS {
protected LinkedList<PCB> processQueue;
public FCFS() {
processQueue = new LinkedList<PCB>();
}
public void schedule() {
sortByArriveTime(processQueue);
int currentTime = 0;
int arriveTime;
PCB process;
Iterator<PCB> iter = processQueue.iterator();
while (iter.hasNext()) {
process = iter.next();
arriveTime = process.getArriveTime();
System.out.print("進程:" + process.getPid() + ",");
System.out.print("到達時間:" + process.getArriveTime() + ",");
System.out.print("需要時間:" + process.getNeedTime() + ",");
if (arriveTime > currentTime)
currentTime = arriveTime;
System.out.print("開始時間:" + currentTime + ",");
currentTime += process.getNeedTime();
System.out.println("結束時間:" + currentTime);
iter.remove();
}
}
public void addProcess(int pid, int arriveTime, int needTime) {
processQueue.push(new PCB(pid, arriveTime, needTime));
}
/**
* 對進程隊列按到達時間排序
*
* @param processQueue
*/
private <T> void sortByArriveTime(LinkedList<PCB> processQueue) {
processQueue.sort((p1, p2) -> {
Integer p1Time = p1.getArriveTime();
Integer p2Time = p2.getArriveTime();
return p1Time.compareTo(p2Time);
});
}
}
具體思想是用隨機數生成多個PCB對象,放入FCFS的進程隊列processQueue中,調度算法首先按照進程的到達時間遞增排序,然後再從進程隊列中依次取出進程,計算其開始時間、結束時間。
2.短作業優先(short job first,SJF)調度算法
短作業(進程)優先調度算法(SJF),是指對短作業或短進程優先調度的算法。它們可以分別用於作業調度和進程調度。短作業優先(SJF)的調度算法是從後備隊列中選擇一個或若干個估計運行時間最短的作業,將它們調入內存運行。而短進程優先(SPF)調度算法則是從就緒隊列中選出一個估計運行時間最短的進程,將處理機分配給它,使它立即執行並一直執行到完成,或發生某事件而被阻塞放棄處理機時再重新調度。
模擬算法如下:
package process.schedule;
import java.util.Comparator;
import java.util.LinkedList;
import controlblock.PCB;
import dispatcher.Dispatcher;
/**
* 短作業優先調度
*
* @author wz
*
* @date 2015年11月10日
*/
public class SJF{
protected LinkedList<PCB> processQueue;
public SJF() {
processQueue = new LinkedList<PCB>();
}
public void schedule() {
sortByArriveTime(processQueue);
PCB process, tempProcess;
int arriveTime, needTime, minIndex, minNeedTime, currentTime = 0;
while (!processQueue.isEmpty()) {
process = processQueue.pollFirst();
arriveTime = process.getArriveTime();
needTime = process.getNeedTime();
if (currentTime < arriveTime)
currentTime = arriveTime;
minIndex = -1;
minNeedTime = Dispatcher.getMaxNeedTime() + 2;
// 要執行進程時,挑選已到達的需要作業時間最短的進程
for (int i = 0; i < processQueue.size(); i++) {
tempProcess = processQueue.get(i);
if (tempProcess.getArriveTime() > currentTime + needTime)
break;
// 到達時間相同,挑選最短作業爲當前作業
if (tempProcess.getArriveTime() == arriveTime && tempProcess.getNeedTime() < needTime) {
processQueue.set(i, process);
process = tempProcess;
tempProcess = processQueue.get(i);
needTime = process.getNeedTime();
}
if (tempProcess.getNeedTime() < minNeedTime) {
minIndex = i;
minNeedTime = tempProcess.getNeedTime();
}
}
// 將最短作業放入隊首
if (minIndex != -1) {
tempProcess = processQueue.remove(minIndex);
processQueue.addFirst(tempProcess);
}
System.out.print("進程:" + process.getPid() + ",到達時間:" + process.getArriveTime() + ",需要時間:"
+ process.getNeedTime() + ",開始時間:" + currentTime + ",");
currentTime += needTime;
System.out.println("結束時間:" + currentTime);
}
}
public void addProcess(int pid, int arriveTime, int needTime) {
PCB process = new PCB(pid, arriveTime, needTime);
processQueue.push(process);
}
/**
* 對進程隊列按到達時間排序
*
* @param processQueue
*/
private <T> void sortByArriveTime(LinkedList<PCB> processQueue) {
processQueue.sort((p1, p2) -> {
Integer p1Time = p1.getArriveTime();
Integer p2Time = p2.getArriveTime();
return p1Time.compareTo(p2Time);
});
}
}
具體思想是用隨機數生成多個PCB對象,放入SJF的進程隊列processQueue中,然後:
①調度算法首先按照進程的到達時間遞增排序,然後在隊列不爲空的情況下執行②
②隊首PCB出隊(本次要執行的作業)
③遍歷進程隊列,若有到達時間與出隊PCB相同,則找出所需作業時間最短的作業,兩者交換。(確保當前作業爲最短作業)
④找出已出隊進程的執行結束時間前到達的所有作業中所需作業時間最短作業程(查找下一個要執行的作業),放入隊首
⑤計算已出隊進程(本次的最短作業)運行的開始時間、結束時間。
⑥若隊列不爲空,執行②,否則結束
3.高響應比優先調度算法(Heigest Response Ratio Next,HRRN)
在批處理系統中,短作業優先算法是一種比較好的算法,其主要的不足之處是長作業的運行得不到保證,容易出現飢餓現象。爲每個作業引入前面所述的動態優先權,並使作業的優先級隨着等待時間的增加而以速率a 提高,則長作業在等待一定的時間後,必然有機會分配到處理機。該優先權的變化規律可描述爲:
由於等待時間與服務時間之和就是系統對該作業的響應時間,故該優先權又相當於響應比RP。據此,又可表示爲:
模擬算法如下:
package process.schedule;
import java.util.Comparator;
import java.util.LinkedList;
import controlblock.PCB;
/**
* 高響應比優先調度
*
* @author wz
*
* @date 2015年11月10日
*/
public class HRRN {
protected LinkedList<PCB> processQueue;
public HRRN() {
processQueue = new LinkedList<PCB>();
}
public void schedule() {
sortByArriveTime(processQueue);
PCB process, tempProcess;
int arriveTime, needTime, maxIndex, currentTime = 0;
double respRatio, maxPriority = 0;
while (!processQueue.isEmpty()) {
process = processQueue.pollFirst();
arriveTime = process.getArriveTime();
needTime = process.getNeedTime();
if (currentTime < arriveTime)
currentTime = arriveTime;
maxIndex = -1;
maxPriority = -1;
// 當前進程執行完後,挑選已到達的響應比最高的進程
for (int i = 0; i < processQueue.size(); i++) {
tempProcess = processQueue.get(i);
if (tempProcess.getArriveTime() > currentTime + needTime)
break;
respRatio = (currentTime + needTime - tempProcess.getArriveTime()) / (double) tempProcess.getNeedTime() + 1;
tempProcess.setPriority(respRatio);
if (respRatio > maxPriority) {
maxIndex = i;
maxPriority = respRatio;
}
}
// 將響應比最高的進程放入隊首
if (maxIndex != -1) {
tempProcess = processQueue.remove(maxIndex);
processQueue.addFirst(tempProcess);
}
System.out.print("進程:" + process.getPid() + ",響應比:" + process.getPriority() + ",到達時間:"
+ process.getArriveTime() + ",需要時間:" + process.getNeedTime() + ",開始時間:" + currentTime + ",");
currentTime += needTime;
System.out.println("結束時間:" + currentTime);
}
}
public void addProcess(int pid, int arriveTime, int needTime) {
PCB process = new PCB(pid, arriveTime, needTime);
processQueue.push(process);
}
/**
* 對進程隊列按到達時間排序
*
* @param processQueue
*/
private <T> void sortByArriveTime(LinkedList<PCB> processQueue) {
processQueue.sort((p1, p2) -> {
Integer p1Time = p1.getArriveTime();
Integer p2Time = p2.getArriveTime();
return p1Time.compareTo(p2Time);
});
}
}
具體思想是用隨機數生成多個PCB對象,放入HRRN的進程隊列processQueue中,然後:
①按照進程的到達時間遞增排序,在隊列不爲空的情況下執行②
②隊首PCB出隊(本次要執行的作業)
③遍歷進程隊列中已出隊作業的執行結束時間前到達的所有作業,計算響應比,找出最高響應比的作業,放入隊首
④計算已出隊進程(本次的響應比最高的作業)運行的開始時間、結束時間。
⑤若隊列不爲空,執行②,否則結束
4.時間片輪轉法(round robin,RR)
在早期的時間片輪轉法中,系統將所有的就緒進程按先來先服務的原則排成一個隊列,每次調度時,把CPU 分配給隊首進程,並令其執行一個時間片。時間片的大小從幾ms 到幾百ms。當執行的時間片用完時,由一個計時器發出時鐘中斷請求,調度程序便據此信號來停止該進程的執行,並將它送往就緒隊列的末尾;然後,再把處理機分配給就緒隊列中新的隊首進程,同時也讓它執行一個時間片。這樣就可以保證就緒隊列中的所有進程在一給定的時間內均能獲得一時間片的處理機執行時間。換言之,系統能在給定的時間內響應所有用戶的請求。
模擬算法如下:
package process.schedule;
import java.util.Comparator;
import java.util.LinkedList;
import controlblock.PCB;
/**
* 時間片輪轉調度
*
* @author wz
*
* @date 2015年11月10日
*/
public class RR {
protected LinkedList<PCB> processQueue;
private static final int TIME_SLICE = 5;
public RR() {
processQueue = new LinkedList<PCB>();
}
public void schedule() {
sortByArriveTime(processQueue);
PCB process;
int currentTime = 0;
int arriveTime;
int needTime;
while (!processQueue.isEmpty()) {
process = processQueue.pollFirst();
needTime = process.getNeedTime();
arriveTime = process.getArriveTime();
System.out.print("進程:" + process.getPid() + ",");
System.out.print("到達時間:" + process.getArriveTime() + ",");
System.out.print("還需要時間:" + process.getNeedTime() + ",");
if (currentTime < arriveTime)
currentTime = arriveTime;
System.out.print("開始時間:" + currentTime + ",");
if (TIME_SLICE < needTime) {
currentTime += TIME_SLICE;
System.out.println("進程中斷時間:" + currentTime);
process.setNeedTime(needTime - TIME_SLICE);
for (int i = 0; i < processQueue.size(); i++) {
if (processQueue.get(i).getArriveTime() > currentTime) {
processQueue.add(i, process);
break;
} else if (i == processQueue.size() - 1) {
processQueue.add(process);
break;
}
}
} else {
currentTime += needTime;
System.out.println("結束時間:" + currentTime);
}
}
}
public void addProcess(int pid, int arriveTime, int needTime) {
processQueue.push(new PCB(pid, arriveTime, needTime));
}
/**
* 對進程隊列按到達時間排序
*
* @param processQueue
*/
private <T> void sortByArriveTime(LinkedList<PCB> processQueue) {
processQueue.sort((p1, p2) -> {
Integer p1Time = p1.getArriveTime();
Integer p2Time = p2.getArriveTime();
return p1Time.compareTo(p2Time);
});
}
}
具體思想是用隨機數生成多個PCB對象,放入RR的進程隊列processQueue中,然後:
①按照進程的到達時間遞增排序,在隊列不爲空的情況下執行②
②隊首PCB出隊(本次要執行的作業)
③爲已出隊進程分配時間片,計算運行的開始時間、中斷時間或結束時間。
④若出隊進程沒有執行完,則將該PCB插入到進程隊列中當前進程中斷時間前所到達的作業的最後
⑤若隊列不爲空,執行②,否則結束
5.優先級調度算法(priority-scheduling algorithm,PSA)
此算法常被用於批處理系統中,作爲作業調度算法,也作爲多種操作系統中的進程調度算法,還可用於實時系統中。當把該算法用於作業調度時,系統將從後備隊列中選擇若干個優先權最高的作業裝入內存。當用於進程調度時,該算法是把處理機分配給就緒隊列中優先權最高的進程,這時,又可進一步把該算法分爲搶佔式(Preemptive Mode)和非搶佔式(Nonpreemptive Mode)。
這裏的調度算法採用搶佔式(Preemptive Mode)優先級調度。
在這種方式下,系統同樣是把處理機分配給優先權最高的進程,使之執行。但在其執行期間,只要又出現了另一個其優先權更高的進程,進程調度程序就立即停止當前進程(原優先權最高的進程)的執行,重新將處理機分配給新到的優先權最高的進程。因此,在採用這種調度算法時,是每當系統中出現一個新的就緒進程i 時,就將其優先權Pi與正在執行的進程j 的優先權Pj進行比較。如果Pi≤Pj,原進程Pj便繼續執行;但如果是Pi>Pj,則立即停止Pj的執行,做進程切換,使i 進程投入執行。顯然,這種搶佔式的優先權調度算法能更好地滿足緊迫作業的要求,故而常用於要求比較嚴格的實時系統中,以及對性能要求較高的批處理和分時系統中。
模擬算法如下:
package process.schedule;
import controlblock.PCB;
import java.util.LinkedList;
import java.util.List;
/**
* 優先權調度(搶佔式)
*
* @author wz
*
* @date 2015年11月10日
*/
public class PSA {
protected LinkedList<PCB> processQueue;
public PSA() {
processQueue = new LinkedList<>();
}
public void schedule() {
sortByArriveTime(processQueue);
PCB process, tempProcess;
int arriveTime, needTime, runTime, currentTime = 0;
while (!processQueue.isEmpty()) {
process = processQueue.pollFirst();
arriveTime = process.getArriveTime();
if (currentTime < arriveTime)
currentTime = arriveTime;
for (int i = 0; i < processQueue.size(); i++) {
needTime = process.getNeedTime();
tempProcess = processQueue.get(i);
if (tempProcess.getArriveTime() > currentTime + needTime)
break;
// 當前進程執行至被高優先級進程搶佔
if (tempProcess.getPriority() < process.getPriority()) {
if (tempProcess.getArriveTime() != currentTime) {
processQueue.remove(i);
System.out.print("進程:" + process.getPid() + ",優先級:" + (int) process.getPriority() + ",到達時間:"
+ process.getArriveTime() + ",需要時間:" + process.getNeedTime() + ",開始時間:" + currentTime
+ ",");
runTime = tempProcess.getArriveTime() - currentTime;
process.setNeedTime(needTime - runTime);
currentTime += runTime;
System.out.println("進程中斷時間:" + currentTime);
processQueue.addFirst(process);
process = tempProcess;
} else {
processQueue.set(i, process);
process = tempProcess;
tempProcess = processQueue.get(i);
// needTime = process.getNeedTime();
}
} else {
subSortByPriority(processQueue, 0, i + 1);
}
}
System.out.print("進程:" + process.getPid() + ",優先級:" + (int) process.getPriority() + ",到達時間:"
+ process.getArriveTime() + ",需要時間:" + process.getNeedTime() + ",開始時間:" + currentTime + ",");
currentTime += process.getNeedTime();
System.out.println("結束時間:" + currentTime);
}
}
public void addProcess(int pid, int priority, int arriveTime, int needTime) {
processQueue.push(new PCB(pid, priority, arriveTime, needTime));
}
/**
* 對進程隊列按到達時間排序
*
* @param processQueue
*/
private <T> void sortByArriveTime(LinkedList<PCB> processQueue) {
processQueue.sort((p1, p2) -> {
Integer p1Time = p1.getArriveTime();
Integer p2Time = p2.getArriveTime();
return p1Time.compareTo(p2Time);
});
}
/**
* 對指定子隊列按優先級排序
*
* @param processQueue
* @param fromIndex
* @param toIndex
*/
private void subSortByPriority(LinkedList<PCB> processQueue, int fromIndex, int toIndex) {
List<PCB> subQueue = processQueue.subList(fromIndex, toIndex);
subQueue.sort((p1, p2) -> {
Double p1Priority = p1.getPriority();
Double p2Priority = p2.getPriority();
return p1Priority.compareTo(p2Priority);
});
}
}
具體思想是用隨機數生成多個PCB對象,放入PSA的進程隊列processQueue中,然後:
①按照進程的到達時間遞增排序,在隊列不爲空的情況下執行②
②隊首PCB出隊(第一個到達的作業或優先級最高的作業)
③遍歷進程隊列,查找當前PCB結束時間前到達的所有PCB,若優先級高於當前執行的作業,執行④,否則執行⑤
④此時當前作業執行至被高優先級作業搶佔。計算當前作業本次運行的開始時間、中斷時間,並放入隊首(優先級高的放在隊首,當前執行作業是目前已查找到的優先級次高的作業),將③查找到的高優先級的作業出隊,成爲當前執行的作業(高優先級作業搶佔處理機)。然後繼續執行③向後遍歷
⑤對隊列中已經遍歷的PCB按優先級遞減就地排序(保證已到達進程按優先級遞減排列)。若未遍歷完,繼續執行③向後遍歷
⑥計算當前進程本次執行的開始時間、結束時間。
⑦若隊列不爲空,執行②,否則結束
暫時就寫了這幾種調度算法的模擬,下面是生成隨機PCB測試的代碼:
package dispatcher;
import java.util.Random;
import process.schedule.FCFS;
import process.schedule.HRRN;
import process.schedule.PSA;
import process.schedule.RR;
import process.schedule.SJF;
/**
* 分派程序
*
* @author wz
*
* @date 2015年11月10日
*/
public class Dispatcher {
private static final int MAX_ARRIVE_TIME = 5;
private static final int MAX_NEED_TIME = 10;
private static final int MAX_PROCESS_NUM = 5;
private static final int MAX_PRIORITY = 10;
private final static int MAX_PID = 10000;
public static void main(String[] args) {
FCFSSchedule();
SJFSchedule();
RRShedule();
PSAShedule();
HRRNShedule();
}
/**
* 高響應比優先調度
*/
private static void HRRNShedule() {
HRRN hrrn = new HRRN();
HRRN ps = hrrn;
Random random = new Random();
for (int i = 0; i < MAX_PROCESS_NUM; i++) {
ps.addProcess(random.nextInt(MAX_PID), random.nextInt(MAX_ARRIVE_TIME), random.nextInt(MAX_NEED_TIME) + 1);
}
ps.schedule();
}
/**
* 優先權調度(搶佔式)
*/
private static void PSAShedule() {
PSA ps = new PSA();
Random random = new Random();
for (int i = 0; i < MAX_PROCESS_NUM; i++) {
ps.addProcess(random.nextInt(MAX_PID), random.nextInt(MAX_PRIORITY), random.nextInt(MAX_ARRIVE_TIME),
random.nextInt(MAX_NEED_TIME) + 1);
}
ps.schedule();
}
/**
* 時間片輪轉調度
*/
private static void RRShedule() {
RR ps = new RR();
Random random = new Random();
for (int i = 0; i < MAX_PROCESS_NUM; i++) {
ps.addProcess(random.nextInt(MAX_PID), random.nextInt(MAX_ARRIVE_TIME), random.nextInt(MAX_NEED_TIME) + 1);
}
ps.schedule();
}
/**
* 先到先服務
*/
private static void FCFSSchedule() {
FCFS ps = new FCFS();
Random random = new Random();
for (int i = 0; i < MAX_PROCESS_NUM; i++) {
ps.addProcess(random.nextInt(MAX_PID), random.nextInt(MAX_ARRIVE_TIME), random.nextInt(MAX_NEED_TIME) + 1);
}
ps.schedule();
}
/**
* 短作業優先調度
*/
private static void SJFSchedule() {
SJF ps = new SJF();
Random random = new Random();
for (int i = 0; i < MAX_PROCESS_NUM; i++) {
ps.addProcess(random.nextInt(MAX_PID), random.nextInt(MAX_ARRIVE_TIME), random.nextInt(MAX_NEED_TIME) + 1);
}
ps.schedule();
}
public static int getMaxNeedTime() {
return MAX_NEED_TIME;
}
}