作业要求:
使用PyQt5、双端队列实现:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton,QComboBox, QTableWidget, QTableWidgetItem
from PyQt5.QtCore import Qt
from collections import deque
class FIFOCache:
def __init__(self, capacity):
self.cache = deque(maxlen=capacity) # 使用deque作为FIFO缓存,设置最大长度为capacity
self.page_faults = 0
self.evicted_page = None # 记录被移除的页面
self.physical_blocks = []
self.flag=0 #记录是否发生页面中断
def refer(self, page,capacity):
self.flag = 0
if page not in self.cache:
self.page_faults += 1 # 页面中断次数加一
self.flag=1
if len(self.cache) == self.cache.maxlen:
self.evicted_page=self.cache.popleft() # 如果缓存已满,FIFO算法中移除最早加入的页面
self.physical_blocks = [page if x == self.evicted_page else x for x in self.physical_blocks]
else:
self.physical_blocks.append(page)
self.cache.append(page) # 将新页面添加到缓存末尾
else:
self.flag = 0
def get_cache(self):
return list(self.cache) # 返回当前缓存中的页面列表
def get_physical_blocks(self):
return self.physical_blocks # 返回物理块列表
def get_flag(self):
return self.flag
class LRUCache:
def __init__(self, capacity):
self.cache = deque(maxlen=capacity) # 使用deque作为LRU缓存,设置最大长度为capacity
self.page_faults = 0
self.evicted_page = None # 记录被移除的页面
self.physical_blocks = []
self.flag=0
def refer(self, page,capacity):
self.flag = 0
if page in self.cache:
self.cache.remove(page) # 如果页面在缓存中,先移除
else:
self.page_faults += 1 # 页面中断次数加一
self.flag=1
if len(self.cache) == self.cache.maxlen:
self.evicted_page=self.cache.popleft() # 如果缓存已满,移除最旧的页面
self.physical_blocks = [page if x == self.evicted_page else x for x in self.physical_blocks]
else:
self.physical_blocks.append(page)
self.cache.append(page) # 将新页面添加到缓存末尾
def get_cache(self):
return list(self.cache) # 返回当前缓存中的页面列表
def get_physical_blocks(self):
return self.physical_blocks # 返回被移除的页面
def get_flag(self):
return self.flag # 返回当前缓存中的页面列表
class PageReplacementSimulator(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Page Replacement Simulator')
layout = QVBoxLayout()
# 输入页面序列的文本框
input_layout1 = QHBoxLayout()
input_layout1.addWidget(QLabel('输入执行页面:'))
self.page_entry = QLineEdit(self)
input_layout1.addWidget(self.page_entry)
# 输入物理块数的文本框
input_layout2 = QHBoxLayout()
input_layout2.addWidget(QLabel('输入物理块数:'))
self.frame_entry = QLineEdit(self)
input_layout2.addWidget(self.frame_entry)
# 页面中断次数的文本框,初始为空,只读且左对齐
input_layout3 = QHBoxLayout()
input_layout3.addWidget(QLabel('页面中断次数:'))
self.page_faults_entry = QLineEdit(self)
self.page_faults_entry.setReadOnly(True) # 设置为只读,避免用户修改
self.page_faults_entry.setAlignment(Qt.AlignLeft) # 左对齐
input_layout3.addWidget(self.page_faults_entry)
# 模拟按钮,点击后触发模拟LRU算法
input_layout4 = QHBoxLayout()
self.algorithm_combo = QComboBox(self)
self.algorithm_combo.addItem("FIFO")
self.algorithm_combo.addItem("LRU")
input_layout4.addWidget(QLabel('Algorithm:'))
input_layout4.addWidget(self.algorithm_combo)
simulate_button = QPushButton('模拟', self)
simulate_button.clicked.connect(self.simulate)
input_layout4.addStretch(1)
input_layout4.addWidget(simulate_button)
layout.addLayout(input_layout1)
layout.addLayout(input_layout2)
layout.addLayout(input_layout3)
layout.addLayout(input_layout4)
self.table = QTableWidget(self)
layout.addWidget(self.table)
self.setLayout(layout)
self.show()
def simulate(self):
selected_algorithm = self.algorithm_combo.currentText()
if selected_algorithm == "FIFO":
self.simulateFIFO()
elif selected_algorithm == "LRU":
self.simulateLRU()
def simulateLRU(self):
page_sequence = list(map(int, self.page_entry.text().split(','))) # 从输入框获取执行页面序列
num_frames = int(self.frame_entry.text()) # 从输入框获取物理块数
lru_cache = LRUCache(num_frames) # 创建LRU缓存对象
self.table.setRowCount(num_frames+ 1) # 设置表格行数为物理块数
self.table.setColumnCount(len(page_sequence)) # 设置表格列数为页面序列的长度
header_labels = [f"({i + 1})-{page_sequence[i]}" for i in range(len(page_sequence))]
self.table.setHorizontalHeaderLabels(header_labels)
for idx, page in enumerate(page_sequence):
lru_cache.refer(page,num_frames) # 调用LRU缓存的refer方法模拟页面置换
flag=lru_cache.get_flag()
cache_content=lru_cache.get_physical_blocks()
for i in range(num_frames):
if i < len(cache_content):
if cache_content[i]==None:
item = QTableWidgetItem("")
item = QTableWidgetItem(str(cache_content[i]))
else:
item = QTableWidgetItem("") # 如果物理块未被填充,显示空字符串
self.table.setItem(i, idx, item)
if flag==1:
item = QTableWidgetItem('X')
else:
item = QTableWidgetItem("")
self.table.setItem(num_frames, idx, item)
self.page_faults_entry.setText(str(lru_cache.page_faults))
def simulateFIFO(self):
page_sequence = list(map(int, self.page_entry.text().split(','))) # 从输入框获取执行页面序列
num_frames = int(self.frame_entry.text()) # 从输入框获取物理块数
fifo_cache = FIFOCache(num_frames) # 创建FIFO缓存对象
self.table.setRowCount(num_frames+1) # 设置表格行数为物理块数
self.table.setColumnCount(len(page_sequence)) # 设置表格列数为页面序列的长度
header_labels = [f"({i + 1})-{page_sequence[i]}" for i in range(len(page_sequence))]
self.table.setHorizontalHeaderLabels(header_labels)
for idx, page in enumerate(page_sequence):
fifo_cache.refer(page,num_frames) # 调用FIFO缓存的refer方法模拟页面置换
flag=fifo_cache.get_flag()
cache_content = fifo_cache.get_physical_blocks()
for i in range(num_frames):
if i < len(cache_content):
item = QTableWidgetItem(str(cache_content[i]))
else:
item = QTableWidgetItem("")
self.table.setItem(i, idx, item)
if flag == 1:
item = QTableWidgetItem('X')
else:
item = QTableWidgetItem("")
self.table.setItem(num_frames, idx, item)
self.page_faults_entry.setText(str(fifo_cache.page_faults)) # 更新页面中断次数显示
if __name__ == '__main__':
app = QApplication(sys.argv)
window = PageReplacementSimulator()
sys.exit(app.exec_())
实例页面序列
2,3,2,1,5,2,4,5,3,2,5,2
结果
FIFO:
LRU: