成组链接法是 UNIX 系统中磁盘空间管理的一种方法。
当系统要为用户分配文件所需的盘块时,须调用盘块分配过程来完成。该过程首先检查空闲盘块号栈是否上锁,如未上锁,便从栈顶取出一空闲盘块号,将与之对应的盘块分配给 用户,然后将栈顶指针下移一格。若该盘块号已是栈底,即 S.free(0),这是当前栈中最后一 个可分配的盘块号。由于在该盘块号所对应的盘块中记有下一组可用的盘块号,因此,须调 用磁盘读过程,将栈底盘块号所对应盘块的内容读入栈中,作为新的盘块号栈的内容,并把 原栈底对应的盘块分配出去(其中的有用数据已读入栈中)。然后,再分配一相应的缓冲区(作 为该盘块的缓冲区)。最后,把栈中的空闲盘块数减 1 并返回。
在系统回收空闲盘块时,须调用盘块回收过程进行回收。它是将回收盘块的盘块号记入 空闲盘块号栈的顶部,并执行空闲盘块数加 1 操作。当栈中空闲盘块号数目已达 100 时,表 示栈已满,便将现有栈中的 100 个盘块号,记入新回收的盘块中,再将其盘块号作为新栈底。
要求:
(1) 了解算法中用的各种数据结构;
(2) 系统初始时可以有4组磁盘块,每组的磁盘块块号随机生成;
(3) 设计分配磁盘块的算法,特别注意的是当第一组只有一个盘块时,分配这个磁盘块时,需要将其中存放的下一组的盘块信息复制到 S.free 数组中。
(4) 设计回收磁盘块的算法,特别注意的是当第一组的有100个盘块时,需要将S.free[0..99]存放的 100 个盘块的信息存放在新回收的盘块中,新回收盘块的盘块号复制到 S.free[0]中。
有简单的界面,用户可以进行分配和回收操作,并查看分配回收后数据结构的变化情况。
#coding=utf-8
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import random
MAXGROUP=10#组的大小
MAXJOB=100#作业最大能申请的块数
class group:
def __init__(self):
self.quantity=0
self.__next=None
self.cell=[]
for i in range(MAXGROUP):
self.cell.append(-1)
def getNext(self):
return self.__next
def setNext(self,newnext):
self.__next=newnext
class job:
def __init__(self):
self.name=''
self.quantity=0
self.__next=None
self.cell=[]
for i in range(MAXJOB):
self.cell.append(-1)
def getNext(self):
return self.__next
def setNext(self,newnext):
self.__next=newnext
groupHead=group()
jobHead=job()
total=0
def readData():
global total
global groupHead
global jobHead
fname='TestUnix.txt'
#while True:
#try:
fn=open(fname,'w')
#break
#except:
#print u'打不开文件',fname
#fname=raw_input('请输入初始空闲块数据文件名:')
f=random.sample(range(200,301),21)
for i in f:
fn.write(str(i)+'\n')
fn.close()
for eachLine in f:
print(eachLine)
if groupHead.quantity<MAXGROUP:
groupHead.cell[groupHead.quantity]=eachLine
groupHead.quantity+=1
else:
p=group()
p.setNext(groupHead)
groupHead=p
p.cell[p.quantity]=eachLine
p.quantity+=1
total+=1
class Application(tk.Tk): # 继承自 tk.Tk
'''界面、逻辑分离示例'''
def __init__(self):
'''初始化'''
super().__init__() # 有点相当于tk.Tk()
self.createWidgets()
def createWidgets(self):
self.tabControl=ttk.Notebook(self)
self.tab1=ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1,text=u'分配')
self.tab2=ttk.Frame(self.tabControl)
self.tabControl.add(self.tab2,text=u'回收')
self.tab3=ttk.Frame(self.tabControl)
self.tabControl.add(self.tab3,text=u'查看')
self.tabControl.pack(expand=1,fill="both")
#-------------------分配--------------------
self.monty=ttk.LabelFrame(self.tab1,text=u'分配展示区')
self.monty.grid(column=0,row=0,padx=8,pady=4)
self.jobname = tk.StringVar()
self.number = tk.IntVar()
self.bids=tk.StringVar()
self.jobname_entry = ttk.Entry(self.monty, width=7, textvariable=self.jobname)
self.jobname_entry.grid(row=1, column=2, sticky=(tk.W, tk.E))
self.jobname_entry.focus()
self.number_entry=ttk.Entry(self.monty,width=7,textvariable=self.number)
self.number_entry.grid(row=2,column=2,sticky=(tk.W,tk.E))
self.number_entry.focus()
# 定义Label部件
ttk.Label(self.monty, textvariable=self.bids,wraplength=80,justify='left').grid(row=3, column=2, sticky=(tk.W, tk.E))
# 定义Button部件
ttk.Button(self.monty, text=u"提交", command=self.bid).grid(row=2, column=3, sticky=tk.W)
# 定义三个Label部件
ttk.Label(self.monty, text=u"请输入新作业名").grid(row=1, column=1, sticky=tk.W)
ttk.Label(self.monty, text=u"所需内存块数").grid(row=2, column=1, sticky=tk.E)
ttk.Label(self.monty, text=u"申请成功,所申请的空闲块流是").grid(row=3, column=1, sticky=tk.W)
#---------------------------------------------
#-------------------回收----------------------
self.monty2=ttk.LabelFrame(self.tab2,text=u'回收展示区')
self.monty2.grid(row=0,column=0,padx=8,pady=4)
self.jobname_entry=ttk.Entry(self.monty2,width=7,textvariable=self.jobname)
self.jobname_entry.grid(row=1,column=2,sticky=(tk.W,tk.E))
self.jobname_entry.focus()
ttk.Label(self.monty2,text=u'请输入要撤销的作业名').grid(row=1,column=1,sticky=tk.W)
ttk.Button(self.monty2,text=u"提交",command=self.callback).grid(row=1,column=3,sticky=tk.W)
#---------------------------------------------
#-------------------查看----------------------
self.tab3.bind("<Button-1>", self.view)
#--------------------------------------------
# 设置每格的 padding
for child in self.monty.winfo_children():
child.grid_configure(padx=5, pady=5)
def view(self,*args):
global groupHead
global total
g_c=[]
for i in range(groupHead.quantity):
g_c.append(groupHead.cell[i])
self.monty3=ttk.LabelFrame(self.tab3,text=u'查看展示区')
self.monty3.grid(row=0,column=0,padx=8,pady=4)
self.group_cell=tk.StringVar()
self.quantity1=tk.IntVar()
self.total1=tk.IntVar()
self.group_first=tk.StringVar()
self.group_cell.set(g_c)
self.quantity1.set(groupHead.quantity)
self.total1.set(total)
self.group_first.set(groupHead.cell[groupHead.quantity-1])
ttk.Label(self.monty3, textvariable=self.group_cell,wraplength=80,justify='left').grid(row=1, column=2, sticky=(tk.W, tk.E))
ttk.Label(self.monty3,textvariable=self.quantity1).grid(row=3,column=2,sticky=(tk.W,tk.E))
ttk.Label(self.monty3,textvariable=self.total1).grid(row=4,column=2,sticky=(tk.W,tk.E))
ttk.Label(self.monty3,textvariable=self.group_first).grid(row=2,column=2,sticky=(tk.W,tk.E))
ttk.Label(self.monty3,text=u'当前栈').grid(row=1,column=1,sticky=tk.W)
ttk.Label(self.monty3,text=u'专用块空闲块数为').grid(row=3,column=1,sticky=tk.W)
ttk.Label(self.monty3,text=u'总空闲块数为').grid(row=4,column=1,sticky=tk.W)
ttk.Label(self.monty3,text=u'当前栈顶为').grid(row=2,column=1,sticky=tk.W)
def bid(self, *args): # 注意:参数必须是带!星!号!的 *args. 否则无论如何都会报类型错误:TypeError
'''逻辑'''
#value = float(self.feet.get()) # 如果前面定义为stringVar: self.feet = StringVar()
#value = self.feet.get()
#self.meters.set('{:.4f}'.format((0.3048 * value * 10000.0 + 0.5)/10000.0))
global total
global jobHead
global groupHead
if self.number.get()>total:
self._msgBox2()
#print u'所需内存块大于当前空闲块数,请稍后再试...'
else:
p=job()
p.name=self.jobname.get()
p.setNext(jobHead.getNext())
jobHead.setNext(p)
p.quantity=self.number.get()
bids=[]
for i in range(self.number.get()):
if groupHead.quantity>1:
bids.append(groupHead.cell[groupHead.quantity-1])
p.cell[i]=groupHead.cell[groupHead.quantity-1]
groupHead.quantity-=1
else:
bids.append(groupHead.cell[0])
p.cell[i]=groupHead.cell[groupHead.quantity-1]
groupHead.quantity-=1
if groupHead.getNext():
groupHead=groupHead.getNext()
total-=1
self.bids.set(bids)
#except ValueError:
# pass
def callback(self,*args):
global jobHead
global groupHead
global total
q=jobHead
p=jobHead.getNext()
r=group()
try:
while p.name and p.name!=self.jobname.get():
if p.getNext():
q=q.getNext()
p=p.getNext()
else:
break
#if p:
for i in range(p.quantity):
if groupHead.quantity<MAXGROUP:
groupHead.cell[groupHead.quantity]=p.cell[i]
groupHead.quantity+=1
else:
r.setNext(groupHead)
groupHead=r
r.cell[r.quantity]=p.cell[i]
r.quantity+=1
total+=p.quantity
q.setNext(p.getNext())
except:
_msgBox1()
#else:
#print u'没有该作业'
#_msgBox1()
def _msgBox1(self):
messagebox.showinfo(u'回收出错', u'没有该作业!')
def _msgBox2(self):
messagebox.showinfo(u'分配出错',u'所需内存块大于当前空闲块数,请重新输入!')
if __name__ == '__main__':
readData()
# 实例化Application
app = Application()
# 设置窗口标题
app.title(u"成组链接法")
# 主消息循环:
app.mainloop()
直接使用了python内置的tkinter模块,当前初始设置生成21个盘块。在分配磁盘块时,特别注意的是当第一组只有一个盘块时,因为都已经分配完了,所以需要将剩下的这个磁盘快中存放的下一组的盘块信息复制到当前这个盘块数组中。回收时也是一样,只不过是倒过来,当前这个数组已经存放满了,就把它们复制到当前第一个盘块指向的下一个数组。
分配
查看当前栈中的盘块号,栈顶是下次分配是先分配出去的盘块
输入要撤销的作业名,将其中的盘块回收