虚拟内存页面置换算法
一、实验环境
编译软件:pycharm
程序语言:python
二、问题描述:
设计程序模拟先来先服务FCFS、最短寻道时间优先SSTF、SCAN和循环SCAN算法的工作过程。假设有n个磁道号所组成的磁道访问序列,给定开始磁道号m和磁头移动的方向(正向或者反向),分别利用不同的磁盘调度算法访问磁道序列,给出每一次访问的磁头移动距离,计算每种算法的平均寻道长度。
三、程序要求:
1)利用先来先服务FCFS、最短寻道时间优先SSTF、SCAN和循环SCAN算法模拟磁道访问过程。
2)模拟四种算法的磁道访问过程,给出每个磁道访问的磁头移动距离。
3)输入:磁道个数n和磁道访问序列,开始磁道号m和磁头移动方向(对SCAN和循环SCAN算法有效),算法选择1-FCFS,2-SSTF,3-SCAN,4-循环SCAN。
4)输出:每种算法的平均寻道长度。
四、实现提示:
用C++语言实现提示:
1)程序中进程调度时间变量描述如下:
const int MaxNumber=100;
int TrackOrder[MaxNumber];
int MoveDistance[MaxNumber];
double AverageDistance;
bool direction;
2)进程调度的实现过程如下:
- 变量初始化;
- 接收用户输入磁道个数n和磁盘访问序列,选择算法1-FCFS,2-SSTF,3-SCAN,4-循环SCAN,输入开始磁盘号m和磁头移动方向;
- 根据用户选择的算法进行磁道访问,输出磁盘调度算法的模拟过程;
- 计算选择每次移动的磁头移动距离和算法的平均寻道长度;
- 输出选择算法的平均寻道长度。
五、程序设计与结果分析
(一)程序设计
(1)先来先服务FCFS
设计思想:根据进程请求访问磁盘的先后次序进行调度。
源代码:
def FCFS(access_sequence, start):
total_head_movement = 0 # 总移动距离
movements = [] # 存储每次移动的距离
for request in access_sequence:
movement = abs(request - start) # 计算当前请求磁道号与起始磁道号的距离
total_head_movement += movement # 累加总移动距离
movements.append(movement) # 将当前移动距离加入列表
start = request # 更新起始磁道号为当前请求磁道号
print(f"移动到磁道 {request}") # 输出当前移动到的磁道号
print(f"移动距离{movements}") # 输出每次移动的距离列表
print(f"磁道访问序列: {access_sequence}")#输出磁道访问序列
avg_seek_length = total_head_movement / len(access_sequence) # 计算平均寻道长度
return avg_seek_length # 返回平均寻道长度
(2)最短寻道时间优先SSTF
设计思想:要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短。
源代码:
def SSTF(access_sequence, start):
total_head_movement = 0 # 初始化总移动距离
visited_sequence = [] # 存储访问顺序的列表
movements = [] # 存储每次移动距离的列表
# 当访问序列不为空时进行循环
while access_sequence:
# 找到最接近当前位置的磁道
closest = min(access_sequence, key=lambda x: abs(x - start))
movement = abs(closest - start) # 计算移动距离
total_head_movement += movement # 更新总移动距离
movements.append(movement) # 记录移动距离
start = closest # 更新当前位置为最近磁道位置
access_sequence.remove(closest) # 从访问序列中移除当前访问的磁道
visited_sequence.append(closest) # 记录访问顺序
print(f"移动到磁道 {closest},移动距离 {movement}") # 打印当前移动信息
# 打印最终的磁道访问序列和移动距离
print(f"磁道访问序列: {visited_sequence}")
print(f"移动距离(磁道数): {movements}")
# 计算平均寻道长度(如果访问序列不为空)
avg_seek_length = total_head_movement / len(visited_sequence)
return avg_seek_length # 返回平均寻道长度
(3)扫描(SCAN)算法
设计思想:
赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t。当需淘汰一个页面时,选择现有页面中其t值最大的,即最久未使用的页面予以淘汰。基于优先级的调度算法,当有新进程的请求到达,且其所要访问的磁道与磁头当前所在磁道的距离较近,则该新的进程请求优先满足;扫描算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑磁头当前的移动方向。
源代码:
def SCAN(access_sequence, start, direction):
total_head_movement = 0 # 初始化总移动距离
visited_sequence = [] # 存储访问序列
movements = [] # 存储移动距离
# 根据方向对访问序列进行排序(正向或反向)
if direction == "forward":
access_sequence.sort()
else:
access_sequence.sort(reverse=True)
# 当访问序列不为空时进行循环
while access_sequence:
# 根据方向找到最近的磁道
if direction == "forward":
closest = min(filter(lambda x: x >= start, access_sequence), default=None)
if closest is None:
direction = "backward"
continue
else:
closest = max(filter(lambda x: x <= start, access_sequence), default=None)
if closest is None:
direction = "forward"
continue
# 计算移动距离并更新总移动距离
movement = abs(closest - start)
total_head_movement += movement
movements.append(movement) # 记录移动距离
start = closest # 更新当前位置为找到的磁道
access_sequence.remove(closest) # 移除已访问的磁道
visited_sequence.append(closest) # 记录访问的磁道
print(f"移动到磁道 {closest},移动距离 {movement}")
# 打印访问序列和移动距离
print(f"磁道访问序列: {visited_sequence}")
print(f"移动距离(磁道数): {movements}")
# 计算平均寻道长度(如果访问序列不为空)
avg_seek_length = total_head_movement / len(visited_sequence)
return avg_seek_length
(4)循环扫描(CSCAN)算法
设计思想:CSCAN算法规定磁头单向移动,最小磁道号紧接着最大磁道号构成循环,进行循环扫描。
源代码:
def C_SCAN(access_sequence, start, direction):
total_head_movement = 0 # 初始化总移动距离
visited_sequence = [] # 存储访问序列
movements = [] # 存储移动距离
access_sequence.sort() # 对访问序列进行排序
# 当访问序列不为空时进行循环
while access_sequence:
# 根据方向找到最近的磁道
if direction == "forward":
closest = min(filter(lambda x: x >= start, access_sequence), default=None)
if closest is None:
closest = access_sequence[0]
else:
closest = max(filter(lambda x: x <= start, access_sequence), default=None)
if closest is None:
closest = access_sequence[-1]
# 计算移动距离并更新总移动距离
movement = abs(closest - start)
total_head_movement += movement
movements.append(movement) # 记录移动距离
start = closest # 更新当前位置为找到的磁道
access_sequence.remove(closest) # 移除已访问的磁道
visited_sequence.append(closest) # 记录访问的磁道
print(f"移动到磁道 {closest},移动距离 {movement}") # 打印当前移动信息
# 打印访问序列和移动距离
print(f"磁道访问序列: {visited_sequence}")
print(f"移动距离(磁道数): {movements}")
# 计算平均寻道长度(如果访问序列不为空)
avg_seek_length = total_head_movement / len(visited_sequence) if len(visited_sequence) > 0 else 0
return avg_seek_length
(4)主程序
# 主程序
n = int(input("输入磁道数目: "))
access_sequence = list(map(int, input("输入磁道访问序列: ").split()))
start = int(input("输入起始磁道: "))
direction = input("输入移动方向 (forward 或 backward): ")
algorithm_choice = int(input("选择算法 (1-FCFS, 2-SSTF, 3-SCAN, 4-C-SCAN): "))
if algorithm_choice == 1:
avg_seek_length = FCFS(access_sequence, start)
elif algorithm_choice == 2:
avg_seek_length = SSTF(access_sequence, start)
elif algorithm_choice == 3:
avg_seek_length = SCAN(access_sequence, start, direction)
elif algorithm_choice == 4:
avg_seek_length = C_SCAN(access_sequence, start, direction)
else:
print("选择无效")
print(f"平均寻道长度: {avg_seek_length}")
(二)运行结果
1.先来先服务FCFS算法运行结果:
2.最短寻道时间算法运行结果:
3.扫描(SCAN)算法运行结果:
4.循环扫描(CSCAN)算法运行结果:
(三)结果分析
根据实验数据绘制上面的结果对比图并结合各算法的设计原理,可以得出以下结论:
- 先来先服务(FCFS)算法对比其他算法平均寻道距离最大,FCFS中每个进程的请求都能依次地得到处理,不会出现某各进程的请求长期得不到满足的情况,所以适用于进程数目较少的场合。
- SSTF算法平均每次磁头移动的距离明显低于FCFS算法的距离,SSTF较FCFS有更好的寻道性能。SSTF与SCAN算法的平均寻道距离较为接近。
- SCAN算法能够提供较小的平均寻到长度,因为它按照一个方向依次服务请求,然后改变方向,避免了某些请求长时间等待。在平均情况下,磁头的平均移动距离相对较少。SCAN算法和CSCAN算法在每次访问磁道号的移动距离上具有较为相似的表现,但是SCAN算法具有更优的平均寻道长度。
- CSCAN的平均寻道距离在四个算法中处于中等的位置,从理论上分析,CSCAN在处理请求进程的请求延迟方面具有优势。