实验目的
通过动态优先权算法的模拟加深对进程概念进程调度过程的理解。
实验内容
(1)用C语言来实现对N个进程采用动态优先权优先算法的进程调度。
(2)每个用来标识进程的进程控制块PCB用结构来描述,包括以下字段:
•••• 进程标识数 ID。
•••• 进程优先数 PRIORITY,并规定优先数越大的进程,其优先权越高。
•••• 进程已占用的CPU时间CPUTIME。
•••• 进程还需占用的CPU时间ALLTIME。当进程运行完毕时,ALLTIME变为0。
•••• 进程的阻塞时间STARTBLOCK,表示当进程再运行STARTBLOCK个时间片后,将进入阻塞状态。
•••• 进程被阻塞的时间BLOCKTIME,表示已足赛的进程再等待BLOCKTIME个时间片后,将转换成就绪状态
•••• 进程状态START。
•••• 队列指针NEXT,用来将PCB排成队列。
(3)优先数改变的原则:
•••进程在就绪队列中呆一个时间片,优先数加1。
•••进程每运行一个时间片,优先数减3。
(4)假设在调度前,系统中有5个进程,它们的初始状态如下:
ID 0 1 2 3 4
PRIORITY 9 38 30 29 0
CPUTIME 0 0 0 0 0
ALLTIME 3 3 6 3 4
STARTBLOCK 2 -1 -1 -1 -1
BLOCKTIME 3 0 0 0 0
STATE READY READY READY READY READY
详细的步骤和思路全部在代码注释中,保证你看一遍就知道代码的意思,阅读起来没有任何难度
//定义一个PCB对象
function PCB(ID, Priority, Cputime, Alltime, Startblock, BlockTime, state) {
this.ID = ID //进程ID
this.Priority = Priority //进程优先级
this.Cputime = Cputime //进程已占用的事件
this.Alltime = Alltime //进程需要占用的时间
this.Startblock = Startblock //进程需阻塞时间
this.BlockTime = BlockTime //进程阻塞的时间
this.state = state //进程状态
}
//定义五个进程
let One = new PCB(0, 9, 0, 3, 2, 3, "Start")
let Two = new PCB(1, 38, 0, 3, -1, 0, "Start")
let Three = new PCB(2, 30, 0, 6, -1, 0, "Start")
let Four = new PCB(3, 29, 0, 3, -1, 0, "Start")
let Five = new PCB(4, 0, 0, 4, -1, 0, "Start")
//就绪队列
let readyqueue = []
//阻塞队列
let blockqueue = []
//临时队列,存储初始队列
let tempqueue = []
//执行完的队列
let overqueue = []
//定义一个数组(队列)
readyqueue = [One, Two, Three, Four, Five]
//正在进行的进程
let runProgress = new PCB()
// 就绪队列优先权排序
/**
* Sort的排序是按照队列各个元素的Priority(也就是优先权排队的)
* 每次排完以后,优先权最大的在数组后面,这样每次运行主程序只需要
* 将最后一个拿出来就是要被运行的进程
*
*/
function Sort(start) {
//sort函数 里面自己写一个函数,用来比较对象内的属性(默认的sort往往是不能够使用的)
function sortBy(field) {
return function(a, b) {
return a[field] - b[field];
}
}
start.sort(sortBy("Priority"));
return start
}
//定义一个展示的界面
function showWindow(start) {
let str1 = ''
let str2 = ''
let str3 = ""
let str4 = ""
let str5 = ""
let str6 = ""
let str7 = ""
for (let i = 0; i < start.length; i++) {
str1 = str1 + " " + start[i].ID;
str2 = str2 + " " + start[i].Priority;
str3 = str3 + " " + start[i].Cputime;
str4 = str4 + " " + start[i].Alltime;
str5 = str5 + " " + start[i].Startblock;
str6 = str6 + " " + start[i].BlockTime;
str7 = str7 + " " + start[i].state;
}
console.log("------------------------------------------------")
console.log("| ID " + str1 + " |")
console.log("| Priority " + str2 + " |")
console.log("| Cputime " + str3 + " |")
console.log("| AllTime " + str4 + " |")
console.log("| StackBlock " + str5 + " |")
console.log("| BlockTime " + str6 + " |")
console.log("| State " + str7 + " |")
console.log("#################################################")
showID("blockqueue", blockqueue)
showID("overqueue", overqueue)
console.log("------------------------------------------------")
}
function showID(str1, arr) {
let str = ""
for (let i = 0; i < arr.length; i++) {
str += " " + arr[i].ID
}
console.log(str1 + "里面的进程有:" + str)
}
//阻塞队列更新
/**
* 阻塞队列的更新一共有两个参数,因为阻塞中的进程,如果他的阻塞时间(BlockTime)等于0
* 意味着它的阻塞时间已经到了,就需要到就绪队列中
* 进入就绪队列以后就要对就绪队列进行重新排序找出优先权最大的那个
*/
function blockqueueUpdata(blockqueue, readyqueue) {
if (blockqueue.length != 0) {
for (item of blockqueue) {
item.BlockTime--
if (item.BlockTime == 0) {
readyqueue.push(item)
blockqueue.pop()
readyqueue = Sort(readyqueue)
break;
}
}
}
}
//就绪队列更新
/**
* 对就绪队列的更新,需要明白最后一个进程是不能更新的
* 因为最后一个进程是优先权最大的那个,那个进程是正在运行的进程,严格意义上说它不算是就绪队列的
* 所以我们只需要对除了最后一个元素的其他元素进行优先权+1的操作
*/
function readyqueueUpdata(readyqueue) {
for (let i = 0; i <= readyqueue.length - 2; i++) {
readyqueue[i].Priority++
}
}
//index记录运行个时间片
let index = 0
//运行一个时间片
function run(readyqueue) {
readyqueue = Sort(readyqueue) //运行之前 先对就绪队列排序
console.log("第" + index + "次")
//这个地方展示的结果是每次运行前的结果,变化后的结构在下一次展示中能看到
showWindow(readyqueue)
/***
* 每运行一次 正在运行的进程的优先权-3 所需时间片-1 已占用CPU时间+1
*/
readyqueue[readyqueue.length - 1].Priority -= 3
readyqueue[readyqueue.length - 1].Alltime -= 1
readyqueue[readyqueue.length - 1].Cputime += 1
//运行完以后需要对就绪队列和阻塞队列进行更新
readyqueueUpdata(readyqueue)
blockqueueUpdata(blockqueue, readyqueue)
/*每次运行都需要把运行进程的的Startblock-1
Startblock=n表示 该进程在运行n个时间片就会进入阻塞队列
*/
readyqueue[readyqueue.length - 1].Startblock -= 1
/*查看就绪队列最后一个(也就是刚刚执行完的优先权最大的那个进程)
他的时间片是否已经运行完了,如果他的Alltime==0 意味着它
运行结束,就可以进入结束队列,不需要在就绪队列呆着(不需要
进行任何操作,其他进程运行与它无关)
*/
if (readyqueue[readyqueue.length - 1].Alltime == 0) {
console.log(readyqueue[readyqueue.length - 1].ID)
readyqueue[readyqueue.length - 1].state = "Finish"
overqueue.push(readyqueue.pop())
}
// 谁的StartBlock==0 就意味该进程需要进入阻塞队列,不能在就绪队列呆着
//因为每次对StartBlock-1 都是对就绪队列最后一个进行操作,所以这个只需要比较最后一个
if (readyqueue.length > 0) {
if (readyqueue[readyqueue.length - 1].Startblock == 0) {
readyqueue[readyqueue.length - 1].state = "Block"
blockqueue.push(readyqueue.pop())
}
}
readyqueue = Sort(readyqueue)
index++
}
//主函数 k的取值我是随便选的 主要判断就是readyqueue.length
//如果等于0就结束操作,你这k 可以为任何值(需要和while一样就行)
function main(readyqueue) {
let k = 0
while (k < 5) {
run(readyqueue)
k = 0
if (readyqueue.length == 0) {
k = 5
}
}
}
main(readyqueue)