[os] LRU 页面置换算法

作业要求: 

使用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:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值