操作系统课程实验3-可变分区存储管理

操作系统课程实验3-可变分区存储管理

一、实验介绍

1.1 实验目的
  1. 加深对可变分区存储管理的理解;
  2. 提高用C语言编制大型系统程序的能力,特别是掌握C语言编程的难点:指针和指针作为函数参数;
  3. 掌握用指针实现链表和在链表上的基本操作。
1.2 实验内容

参照教材P137-P140的内容,编写一个C程序,用循环首次适应算法、最佳适应算法和最坏适应算法,模拟可变分区存储管理,实现对内存区的分配和回收管理。

1.3 实验要求
  1. 每次分配和释放后显示空闲分区表。
  2. 空闲分区表可采用结构数组的形式(最低要求)或双向链表的形式。
1.4 参考测试数据

操作系统在低地址占用100KB的空间,用户区主存从100KB处开始占用512KB。初始时,用户区全部为空闲,分配时截取空闲分区的低地址部分作为已分配区。执行以下申请、释放操作序列后:请求300KB,请求100KB,释放300KB,请求150KB,请求90KB,释放100KB。

二、实现代码

#include<stdio.h>  
#include<stdlib.h> 
#include<iostream> using namespace std; #define ALLOCATED 1 						// 定义已分配状态为1
#define FREE 0 								// 定义空闲状态为0
#define SEQUENCELENGTH 6 					// 定义操作序列长度为6typedef struct CHAIN { 						// 定义链表结构体 Tableint status; 							// 记录块的状态:ALLOCATED 或 FREEint pid; 								// 记录分配给的进程IDint size; 								// 记录块的大小int addr; 								// 记录块的起始地址struct CHAIN *Next_Block; 				// 指向下一块的指针struct CHAIN *Pre_Block; 				// 指向前一块的指针
} Table; Table *Head; 								// 头指针,指向链表的头部
int OCPSequence[SEQUENCELENGTH][3] = { 		// 操作序列数组,包含分配和回收操作{1, 1, 300}, {1, 2, 100}, {2, 1, 300}, {1, 3, 150}, {1, 4, 90}, {2, 2, 100}
};void start(); 								// 声明启动函数void FirstFit(); 							// 声明首次适应算法函数
void BestFit(); 							// 声明最佳适应算法函数
void WorstFit(); 							// 声明最坏适应算法函数
void CirFirstFit(); 						// 声明循环首次适应算法函数bool recycle(int pid); 						// 声明回收函数
void linkprint(void); 						// 声明链表打印函数
void CommomDeal(int alg); 					// 声明通用处理函数Table* FindFF(int size); 					// 声明首次适应算法查找函数
Table* FindBF(int size); 					// 声明最佳适应算法查找函数
Table* FindWF(int size); 					// 声明最坏适应算法查找函数
Table* FindCFF(int size); 					// 声明循环首次适应算法查找函数void HeadReset(void); 						// 声明头节点重置函数int main(void) {Head = (Table*)malloc(sizeof(Table)); 	// 分配内存给头节点Head->Next_Block = Head->Pre_Block = NULL; // 初始化头节点的前后指针HeadReset(); 							// 重置头节点start(); 								// 启动模拟return 0; 
}void start() {cout << "we are gonna do a simulation about memory allocation" << endl; cout << "next,there are some algorithm is waiting for you,you need to choose one of them in every circle" << endl; cout << "1.首次适应算法\t2.最佳适应算法\t3.最坏适应算法\t4.循环首次适应算法" << endl << endl << endl << endl; int IDofAlgorithm; 						// 声明算法ID变量for (int i = 0; i < 4; i++) { 			// 循环4次,模拟4个算法cout << "输入算法ID:"; 			cin >> IDofAlgorithm; 				// 输入算法IDwhile (IDofAlgorithm < 1 || IDofAlgorithm > 4) { // 检查输入是否合法cout << "无效的算法ID,请重新输入:"; cin >> IDofAlgorithm; }switch (IDofAlgorithm) { 			// 根据算法ID选择对应算法case 1:printf("--------------------------------------------------------------------------------------\n                                     首次适应算法                                     \n--------------------------------------------------------------------------------------\n"); // 打印首次适应算法标题FirstFit(); 				// 调用首次适应算法函数break;case 2:printf("--------------------------------------------------------------------------------------\n                                     最佳适应算法                                     \n--------------------------------------------------------------------------------------\n"); // 打印最佳适应算法标题BestFit(); 					// 调用最佳适应算法函数break;case 3:printf("--------------------------------------------------------------------------------------\n                                     最坏适应算法                                     \n--------------------------------------------------------------------------------------\n"); // 打印最坏适应算法标题WorstFit(); 				// 调用最坏适应算法函数break;case 4:printf("--------------------------------------------------------------------------------------\n                                   循环首次适应算法                                   \n--------------------------------------------------------------------------------------\n"); // 打印循环首次适应算法标题CirFirstFit(); 				// 调用循环首次适应算法函数break;}HeadReset(); 						// 重置头节点,准备下一个算法测试}
}void FirstFit() {CommomDeal(1); // 调用通用处理函数,参数为1(首次适应算法)
}
void BestFit() {CommomDeal(2); // 调用通用处理函数,参数为2(最佳适应算法)
}
void WorstFit() {CommomDeal(3); // 调用通用处理函数,参数为3(最坏适应算法)
}Table* FindFF(int size) {Table * p = Head; 					// 初始化指针p为头节点while (p != NULL ) { 				// 遍历链表if (p->size >= size && p->status == FREE) // 找到第一个合适的空闲块return p; 					// 返回该块指针p = p->Next_Block; 				// 移动到下一个块}return NULL; 						// 如果没有合适的块,返回NULL
}Table* FindBF(int size) {Table * p = Head; 					// 初始化指针p为头节点Table * best = NULL; 				// 初始化最优块指针为NULLwhile (p != NULL ) { 				// 遍历链表if (p->status == FREE && p->size >= size && (best == NULL || p->size < best->size)) // 找到更小的合适空闲块best = p; 					// 更新最优块指针p = p->Next_Block; 				// 移动到下一个块}return best; 						// 返回最优块指针
}Table* FindWF(int size) {Table * p = Head; 					// 初始化指针p为头节点Table * Worst = NULL; 				// 初始化最差块指针为NULLwhile (p != NULL ) { 				// 遍历链表if (p->status == FREE && p->size >= size && (Worst == NULL || p->size > Worst->size)) // 找到更大的合适空闲块Worst = p; 					// 更新最差块指针p = p->Next_Block; 				// 移动到下一个块}return Worst; 						// 返回最差块指针
}Table* FindCFF(Table * p, int size) {Table * Flag = p; 					// 保存初始块指针if (p == NULL) 						// 如果初始块为空p = Head; 						// 从头开始while (p != NULL) { 				// 遍历链表if (p->status == FREE && p->size >= size) // 找到合适的空闲块return p; 					// 返回该块指针if (!p->Next_Block) 			// 如果到达链表末尾p = Head; 					// 回到头节点elsep = p->Next_Block; 			// 移动到下一个块if (p == Flag) 					// 如果回到初始块return NULL; 				// 返回NULL表示没有找到合适块}
}void CommomDeal(int alg) {Table* (*Tar)(int); 				// 定义函数指针switch (alg) { 						// 根据算法选择对应查找函数case 1:Tar = FindFF; // 指向首次适应算法查找函数break;case 2:Tar = FindBF; // 指向最佳适应算法查找函数break;case 3:Tar = FindWF; // 指向最坏适应算法查找函数break;}for (int i = 0; i < SEQUENCELENGTH; i++) { 			// 遍历操作序列if (OCPSequence[i][0] == 1) { 					// 分配操作int ID, size;ID = OCPSequence[i][1]; 					// 获取进程IDsize = OCPSequence[i][2]; 					// 获取请求大小Table  *pReturn;printf("进程%d请求%dKB\n", ID, size); 		// 打印请求信息printf("--------------------------------------------------------------------------------------\n");if ((pReturn = Tar(size)) != NULL) { 		// 调用查找函数,找到合适块if (pReturn->size == size) { 			// 如果块大小正好pReturn->pid = ID; 					// 设置块的进程IDpReturn->status = ALLOCATED; 		// 设置块的状态为已分配} else { 								// 如果块大小大于请求大小Table * NewFreeNode = (Table*)malloc(sizeof(Table)); // 创建新空闲块NewFreeNode->pid = -1; 				// 初始化新块NewFreeNode->addr = pReturn->addr + size; // 设置新块地址NewFreeNode->size = pReturn->size - size; // 设置新块大小NewFreeNode->status = FREE; 		// 设置新块状态为空闲pReturn->pid = ID; 					// 设置当前块的进程IDpReturn->size = size; 				// 设置当前块的大小pReturn->status = ALLOCATED; 		// 设置当前块的状态为已分配NewFreeNode->Pre_Block = pReturn; 	// 设置新块的前指针NewFreeNode->Next_Block = pReturn->Next_Block; // 设置新块的后指针pReturn->Next_Block = NewFreeNode; 	// 设置当前块的后指针为新块}} else { 									// 如果没有合适的块cout << "内存不足,分配失败" << endl; 	// 打印失败信息}} else { 										// 回收操作int pid;pid = OCPSequence[i][1]; 					// 获取要回收的进程IDprintf("请求回收进程%d,即将释放内存空间%dKB\n", pid, OCPSequence[i][2]); // 打印回收请求信息if (!recycle(pid)) 							// 调用回收函数cout << "进程不存在,回收失败" << endl; // 打印回收失败信息elsecout << "回收成功" << endl; 			// 打印回收成功信息}linkprint(); 									// 打印当前链表状态printf("--------------------------------------------------------------------------------------\n");}cout << endl << endl << endl;
}void CirFirstFit() {Table *Current = NULL; 								// 初始化当前指针为空for (int i = 0; i < SEQUENCELENGTH; i++) { 			// 遍历操作序列if (OCPSequence[i][0] == 1) { 					// 分配操作int ID, size;ID = OCPSequence[i][1]; 					// 获取进程IDsize = OCPSequence[i][2]; 					// 获取请求大小printf("进程%d请求%dKB\n", ID, size); 		// 打印请求信息printf("--------------------------------------------------------------------------------------\n");if ((Current = FindCFF(Current ? Current->Next_Block : Head, size)) != NULL) { // 调用循环首次适应查找函数if (Current->size == size) { 			// 如果块大小正好Current->pid = ID; 					// 设置块的进程IDCurrent->status = ALLOCATED; 		// 设置块的状态为已分配} else { 								// 如果块大小大于请求大小Table * NewFreeNode = (Table*)malloc(sizeof(Table)); // 创建新空闲块NewFreeNode->pid = -1; 				// 初始化新块NewFreeNode->addr = Current->addr + size; // 设置新块地址NewFreeNode->size = Current->size - size; // 设置新块大小NewFreeNode->status = FREE; 		// 设置新块状态为空闲Current->pid = ID;					// 设置当前块的进程IDCurrent->size = size; 				// 设置当前块的大小Current->status = ALLOCATED; 		// 设置当前块的状态为已分配NewFreeNode->Pre_Block = Current; 	// 设置新块的前指针NewFreeNode->Next_Block = Current->Next_Block; // 设置新块的后指针Current->Next_Block = NewFreeNode; 	// 设置当前块的后指针为新块}} else { 									// 如果没有合适的块cout << "内存不足,分配失败" << endl; 	// 打印失败信息}} else { 										// 回收操作int pid;pid = OCPSequence[i][1]; 					// 获取要回收的进程IDprintf("请求回收进程%d,即将释放内存空间%dKB\n", pid, OCPSequence[i][2]); // 打印回收请求信息if (!recycle(pid)) 							// 调用回收函数cout << "进程不存在,回收失败" << endl; // 打印回收失败信息elsecout << "回收成功" << endl; 			// 打印回收成功信息}linkprint(); 									// 打印当前链表状态printf("--------------------------------------------------------------------------------------\n");}cout << endl << endl << endl;
}bool recycle(int pid) {Table *p = Head; 									// 初始化指针p为头节点while (p) { 										// 遍历链表if (p->pid == pid) { 							// 找到匹配的进程IDp->status = FREE; 							// 设置块状态为空闲// 合并相邻的空闲块if (p->Next_Block && p->Next_Block->status == FREE) { // 如果下一块也是空闲Table *next = p->Next_Block; 			// 保存下一块指针p->size += next->size; 					// 合并大小p->Next_Block = next->Next_Block; 		// 更新当前块的后指针if (next->Next_Block) {next->Next_Block->Pre_Block = p; 	// 更新下一块的前指针}free(next); 							// 释放合并的块}if (p->Pre_Block && p->Pre_Block->status == FREE) { // 如果前一块也是空闲Table *prev = p->Pre_Block; 			// 保存前一块指针prev->size += p->size; 					// 合并大小prev->Next_Block = p->Next_Block; 		// 更新前一块的后指针if (p->Next_Block) {p->Next_Block->Pre_Block = prev; 	// 更新当前块的前指针}free(p); 								// 释放合并的块p = prev; 								// 更新指针p为前一块}return true; 								// 返回回收成功}p = p->Next_Block; 								// 移动到下一个块}return false; 										// 如果没有找到匹配的进程ID,返回回收失败
}void linkprint(void) {Table *p = Head; 									while (p) { 									if (p->status == 0) 							cout << "" << p->addr << "~" << p->addr + p->size << ":" << p->status <<  ""; // 打印空闲块信息else 											cout << "" << p->addr << "~" << p->addr + p->size << ":" << p->status << " by " << p->pid << ""; // 打印已分配块信息if (p->Next_Block) 								cout << "-->"; 								p = p->Next_Block; 								}cout << endl; 									
}void HeadReset(void) {Table* p = Head->Next_Block; 			// 初始化指针p为头节点的下一块Table *temp; 							// 声明临时指针while (p) { 							// 遍历链表temp = p->Next_Block; 				// 保存下一块指针free(p); 							// 释放当前块p = temp; 							// 更新指针p为下一块}Head->addr = 100; 						// 重置头节点地址Head->Next_Block = NULL; 				// 重置头节点后指针Head->Pre_Block = NULL; 				// 重置头节点前指针Head->pid = -1; 						// 重置头节点进程IDHead->size = 500; 						// 重置头节点大小Head->status = FREE; 					// 重置头节点状态为空闲
}

三、心灵的救赎

  1. 人间没有永恒的夜晚,世界没有永恒的冬天。
  2. 当生活把无边的严寒铺盖在你身上时,一定会给你一根火柴。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何设计足够可靠的分布式缓存体系,以满足大中型移动互联网系统的需要?no.31

传统 CAP 的突破 随着分布式系统的不断演进&#xff0c;会不断遇到各种问题&#xff0c;特别是当前&#xff0c;在大中型互联网系统的演进中&#xff0c;私有云、公有云并行发展且相互融合&#xff0c;互联网系统的部署早已突破单个区域&#xff0c;系统拓扑走向全国乃至全球的…

新书推荐:6.2 else if语句

本节必须掌握的知识点&#xff1a; 示例代码二十 代码分析 汇编解析 ■if语句表达形式3 if(表达式1) statement1 else if(表达式2) statement2 else if(表达式3) statement3 …… else statementN 解析&#xff1a; 如果表达式1非0&#xff0c;则执行statement1&#…

记录github小程序短视频系统的搭建过程

GitHub - lkmc2/AwesomeVideoWxApp: 《倾心短视频》微信小程序 这个项目按readme中的来可以部署成功&#xff0c;但是会发现图片、视频全是空的&#xff0c;如下图&#xff1a; 修改源代码&#xff0c;更换图片上传与保存地址 大概涉及到这些代码块&#xff0c;进行更改即可。…

什么样的数据摆渡设备,可以满足不同网间数据的安全传输需求?

数据摆渡设备是用来在不同的网络环境间安全地传输数据的硬件或软件解决方案。它们通常用于确保在具有不同安全级别的网络&#xff08;如内网和外网&#xff09;之间进行数据交换时的安全性和合规性。以下是一些常见的数据摆渡设备和方法&#xff1a; 移动介质拷贝&#xff1a;使…

生产制造边角料核算说明及ODOO演示

今天群里有伙伴提到边角料的处理问题&#xff0c;我们梳理了一下&#xff0c;在生产过程中&#xff0c;如果产生了边角料&#xff0c;核算产成品的投料成本时需要考虑边角料的价值&#xff0c;以确保成本核算的准确性。以下是注意的几点&#xff1a; 一、边角料的入账价值 在生…

OSPF路由聚合

原理概述 与RIP不同&#xff0c;OSPF不支持自动路由聚合&#xff0c;仅支持手动路由聚合。OSPF的路由聚合有两种机制&#xff1a;区域间路由聚合和外部路由聚合。区域间路由聚合必须配置在ABR路由器上&#xff0c;指的是ABR在把与自己直接相连区域&#xff08;Area&#xff09…

K8s 二进制部署---下篇(多master节点 负载均衡 高可用)

一 master02 节点部署 master01192.168.11.5kube-apiserver&#xff0c;kube-controller-manager&#xff0c;kube-scheduler&#xff0c;etcdmaster02192.168.11.12kube-apiserver&#xff0c;kube-controller-manager&#xff0c;kube-scheduler&#xff0c;etcdnode01192.1…

RHEL7及之后系统 系统服务脚本(Rocky 9.4)

目录 源码安装 准备工作 步骤1: 下载软件 步骤2: 安装apr 步骤3: 安装apr-util 步骤4: 安装Apache HTTP Server 总结步骤 后续步骤 源码安装 准备环境&#xff1a;首先&#xff0c;确保你的系统中安装了必要的编译工具和依赖库。对于C/C程序&#xff0c;这通常包括编译器&#…

一阶数字高通滤波器

本文的主要内容包含一阶高通滤波器公式的推导和数字算法的实现以及编程和仿真 1 计算公式推导 1.1.2 算法实现及仿真 利用python实现的代码如下&#xff1a; import numpy as np # from scipy.signal import butter, lfilter, freqz import matplotlib.pyplot as plt #2pifW…

从原理上解决 uniapp (含第三方插件)打包 iOS APP 失败的问题

最近一段时间&#xff0c;我的团队基于uniapp开发的平台型APP因平台资金合规的要求&#xff0c;需要对接中金支付&#xff0c;uniapp的插件市场有一个别人做好的中金支付插件&#xff0c;但前端开发同事在引用这个 插件时&#xff0c;出现了 iOS APP 打包不成功的情况&#xff…

Pantera 合伙人简谈 Morpho:更高效、适应性更强的 DeFi 解决方案

原文标题&#xff1a;《Pioneering Peer-to-Peer Lending in the DeFi Revolution》撰文&#xff1a;Pantera Capital 合伙人 Paul Veradittakit编译&#xff1a;Chris&#xff0c;Techub News 文章来源&#xff1a;香港Web3媒体Techub News Morpho 正在超越 Compound 等传统…

Redis主从、哨兵、cluster集群的部署和细节

目录 1. 主从模式 为什么需要主从&#xff1f; 搭建主从架构 2. Sentinel(哨兵)模式 为什么需要哨兵模式&#xff1f; 搭建哨兵集群 哨兵集群 Go语言编程redis哨兵模式 有了哨兵&#xff0c;客户端连接谁&#xff1f; test1&#xff1a;redis节点主从切换 test2&am…

webgl入门-矩阵变换

矩阵变换 前言 变换有三种状态&#xff1a;平移、旋转、缩放。 当我们变换一个图形时&#xff0c;实际上就是在移动这个图形的所有顶点。 课堂目标 掌握图形变换的三种方式。可以对图像进行复合变换。 知识点 平移旋转缩放 第一章 平移 对图形的平移就是对图形所有顶点…

如何快速从手动测试转向自动化测试

寻求具有无缝持续集成和持续交付 (CI/CD) 的高效 DevOps 管道比以往任何时候都更加重要。想象一下这样一个场景&#xff1a;您的软件组织显著减少了人工工作量、降低了成本&#xff0c;并更加自信地发布了软件更新。换句话说&#xff0c;通过将 Web UI 和 API 测试结合在一起&a…

【小白课程】如何在openKylin上个性化定制开关机动画

开关机动画是Linux系统的重要组成部分&#xff0c;其主要功能是在Linux内核启动的早期遮盖内核打印日志&#xff0c;并在内核刷新屏幕分辨率时保证屏幕显示的流畅性。 其中&#xff0c;openKylin操作系统使用plymouth组件作为开关机动画显示程序。Linux系统在启动时&#xff0…

计算机SCI期刊,中科院2区,收稿范围非常广泛!

一、期刊名称 Journal of Web Semantics 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;2.5 中科院分区&#xff1a;2区 出版方式&#xff1a;开放出版 版面费&#xff1a;$1600 三、期刊征稿范围 《网络语义学杂志》…

【软件测试】5.测试用例

目录 1.测试用例 1.1概念 1.2测试的要素 2.测试用例的万能公式 2.1常规思考逆向思维发散性思维 2.2万能公式 2.2.1功能测试 2.2.2界面测试 2.2.3性能测试 2.2.4兼容性测试 2.2.5易用性测试 2.2.6安全测试 2.3弱网测试 1.测试用例 1.1概念 什么是测试用例&#xf…

Jenkins 构建 Web 项目:构建服务器和部署服务器分离的情况

构建命令 #!/bin/bash node -v pnpm -v pnpm install pnpm build:prod # 将dist打包成dist.zip zip -r dist.zip dist

软件项目运维方案-word原件2024

1. 文档介绍 1.1 文档目的 1.2 文档范围 1.3 读者对象 1.4 参考文献 1.5 术语与缩写解释 2. 人员与责任 2.1 项目建设管理机构 2.2 驻场人员工作时间 2.3 人员培训 2.3.1. 培训需求管理 2.3.2. 培训内容管理 2.4 绩效考核 3. 运维过程内容 3.1. 运维模型 3.2. P…

LangChain - 概念指南

文章目录 一、Architecture1、langchain-core2、partner-packages3、langchain4、langchain-community5、langgraph6、langserve7、langsmith 二、浪链表达语言&#xff08;LCEL &#xff09;可运行界面 runnable-interface 三、组件 components1、聊天模型 chat-models2、 LLM…