操作系统实验-进程控制(python实现)
一、实验目标
模拟操作系统对进程的管理。实现进程之间的切换。
二、实验要求
(1)单处理机,即一次只能 1 个进程处于运行态
(2)内核实现进程切换和进程调度(scheduler&switch)的执行时间忽略,只考虑进程的执行所花时间
(3)程序的指令分为 cpu 和 io 两种类型。 cpu 代表 cpu 指令,执行 cpu 指令需要 1 个时间单位;io 代表 io 指令,需要阻塞该进程,执行 io 指令需要 5 个时间单位(第 1 个时间单位使用 cpu,后面 4 个时间单位使用 IO 设备)
(4)进程的状态有:READY,RUN:cpu, RUN:io, WAITING, DONE
(5)CPU 的状态有:1(忙),0(空闲),IOs 的状态有:1(忙),0(空闲)
三、代码实现
class PCB: #进程pcb
def __init__(self,id): #通过id来区分是哪一个进程
self.id=id #进程id
self.state='ready' #进程初始状态均设置为ready就绪态
self.instruction=[] #进程的指令
self.waitingtime=0 #阻塞标记 io时使用
class queue: #用于进程调度管理的链式队列
def __init__(self):
self.head=None #初始化赋空值
self.tail=None
self.size=0
def isnotempty(self): #判断队列是否为空
if(self.head): #队列非空返回1
return 1
else: #队列为空返回0
return 0
def insert(self,node): #插入一个新节点 尾插
node.next=None
if(self.head==None):#队列为空插入新节点
self.head=node
else: #队列非空插入新节点
self.tail.next=node
self.tail=node
self.size+=1
def remove(self): #将节点从队列取出 同时移出当前队列
node=self.head
#self.size-=1
self.head=self.head.next
if self.isnotempty()==0 :
self.tail=None
return node
def go():
readyqueue=queue()
runningProcess=queue()
waitingqueue=queue()
pid0=PCB('PID0')
pid1=PCB('PID1')
pid2=PCB('PID2')
pid3=PCB('PID3')
pid4=PCB('PID4')
pid5=PCB('PID5')
pid0.instruction=['io','cpu','cpu','io','cpu']
pid1.instruction=['cpu','io','cpu']
pid2.instruction=['io','cpu','cpu','io','io']
pid3.instruction=['io','cpu','io']
pid4.instruction=['cpu','io','cpu','io']
pid5.instruction=['cpu','cpu','cpu','io']
readyqueue.insert(pid0)
readyqueue.insert(pid1)
readyqueue.insert(pid2)
readyqueue.insert(pid3)
readyqueue.insert(pid4)
readyqueue.insert(pid5)
time=0
cputime=0
iotime=0
print('Time ',pid0.id,' ',pid1.id,' ',pid2.id,' ',pid3.id,' ',pid4.id,' ',pid5.id,' ','CPU IOs')
while readyqueue.isnotempty() or runningProcess.isnotempty() or waitingqueue.isnotempty():
usecpu=0
useio=0
if runningProcess.isnotempty():
rh=runningProcess.head
if len(rh.instruction)==0:
rh.state='done'
runningProcess.remove()
if waitingqueue.isnotempty():
wh=waitingqueue.head
while wh!=None:
wh.state='waiting'
wh.waitingtime-=1
wh=wh.next
wh=waitingqueue.head
while wh!=None:
if wh.waitingtime==-1:
if len(wh.instruction):
if runningProcess.isnotempty()==0:
runningProcess.insert(waitingqueue.remove())
else:
readyqueue.insert(waitingqueue.remove())
else:
wh.state='done'
waitingqueue.remove()
wh=wh.next
useio=waitingqueue.size
if readyqueue.isnotempty():
reh=readyqueue.head
while reh!=None :
reh.state='ready'
reh=reh.next
if runningProcess.isnotempty()==0 and readyqueue.isnotempty():
runningProcess.insert(readyqueue.remove())
if runningProcess.isnotempty():
rh=runningProcess.head
if len(rh.instruction):
order=rh.instruction[0]
if order=='cpu' :
rh.state='run:cpu'
del rh.instruction[0]
usecpu+=1
elif order=='io' :
rh.state='run:io'
rh.waitingtime=4
del rh.instruction[0]
waitingqueue.insert(runningProcess.remove())
usecpu+=1
else:
rh.state='done'
runningProcess.remove()
time+=1
print(time,' ',pid0.state,' ',pid1.state,' ',pid2.state,' ',pid3.state,' ',pid4.state,' ',pid5.state,' ',usecpu,' ',useio,sep='\t')
if usecpu!=0 :
cputime+=1
if useio!=0 :
iotime+=1
print('Stats: Total Time ',time)
print('Stats: CPU Busy ',cputime,' (',cputime/time*100,'% )')
print('Stats: IO Busy ',iotime,' (',iotime/time*100,'% )')
if __name__=='__main__':
go()
四、实验结果
管理实验结果如下图所示,其中Time表示时间片,PID0=PID5表示6个进程,其中ready表示进程处于就绪态,run:cpu表示当前正在运行cpu指令,run:io表示正在进行io指令,此时会占用一个时间片的cpu,之后会继续进行三个时间片的阻塞,即waiting状态,done表示此进程指令已经全部执行完成。由于本实验是单处理机,所以CPU这一列表示此时间片是否占用cpu,包括run:io和run:cpu,1表示有cpu被占用,0表示没有cpu被占用。IOs表示此时间片被占用io数量,为0表示无waiting,由于阻塞可以多个进程同时进行,所以其他数字即表示当前时间片waiting总数。Total Time表示总时间片个数,图中表示为执行本程序共用29个时间片,CPU Busy表示占用cpu的时间,图中表示cpu占用24个时间片,后面括号内数字为占用cpu时间与运行程序总时间的比,这里为24/29所得,IO Busy表示占用io的总时间,这里27表示有27个时间片使用了io,后面的百分比是使用io时间与总时间的比,这里是27/29。
五、小结
这里我模拟了操作系统对进程的管理,实现了进程之间的切换,我们应该对操作系统的进程管理有一定的了解,了解进程是如何调度的,如何执行的。这里通过readyqueue、runningProcess、waitingqueue三个队列来管理进程,通过出队入队等操作将进程作为节点在不同队列上切换,并根据不同进程当前指令判断,这样就实现了进程状态的转换,需要要理解操作系统后台对进程是如何进行调度的,操作系统会按照一定逻辑来完成调度,在这里我按照自己的理解来设计,实现了多进程的并发执行,这就需要一定的调度机制,初始时,所有进程均放入就绪队列,然后会从就绪队列取出第一个进程放入执行队列,判断此进程第一个指令是哪种,是cpu指令则执行run:cpu,此时cpu将处于忙碌状态,且由于是单cpu,同一时刻只能有一个进程占用cpu,若是io则执行run:io,此时也会占用cpu,在之后需要将其放入阻塞队列,执行三次waiting,才可以被放回就绪队列,然后还会从就绪队列取进程,如此往复,直到redyqueue和waitingqueue全为空,即所有进程的所有指令都进行完毕,程序结束。
(如有问题,欢迎留言)