操作系统课程实验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 					// 定义操作序列长度为6

typedef struct CHAIN { 						// 定义链表结构体 Table
    int status; 							// 记录块的状态:ALLOCATED 或 FREE
    int pid; 								// 记录分配给的进程ID
    int 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; 				// 输入算法ID
        while (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; 				// 初始化最优块指针为NULL
    while (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; 				// 初始化最差块指针为NULL
    while (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; 					// 回到头节点
        else
            p = 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]; 					// 获取进程ID
            size = 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; 					// 设置块的进程ID
                    pReturn->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; 					// 设置当前块的进程ID
                    pReturn->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]; 					// 获取要回收的进程ID
            printf("请求回收进程%d,即将释放内存空间%dKB\n", pid, OCPSequence[i][2]); // 打印回收请求信息
            if (!recycle(pid)) 							// 调用回收函数
                cout << "进程不存在,回收失败" << endl; // 打印回收失败信息
            else
                cout << "回收成功" << 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]; 					// 获取进程ID
            size = 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; 					// 设置块的进程ID
                    Current->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;					// 设置当前块的进程ID
                    Current->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]; 					// 获取要回收的进程ID
            printf("请求回收进程%d,即将释放内存空间%dKB\n", pid, OCPSequence[i][2]); // 打印回收请求信息
            if (!recycle(pid)) 							// 调用回收函数
                cout << "进程不存在,回收失败" << endl; // 打印回收失败信息
            else
                cout << "回收成功" << endl; 			// 打印回收成功信息
        }
        linkprint(); 									// 打印当前链表状态
        printf("--------------------------------------------------------------------------------------\n");
    }
    cout << endl << endl << endl;
}

bool recycle(int pid) {
    Table *p = Head; 									// 初始化指针p为头节点
    while (p) { 										// 遍历链表
        if (p->pid == pid) { 							// 找到匹配的进程ID
            p->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; 						// 重置头节点进程ID
    Head->size = 500; 						// 重置头节点大小
    Head->status = FREE; 					// 重置头节点状态为空闲
}

三、心灵的救赎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值