C 语言模拟首次适应算法

一、题目描述

某操作系统采用段式管理,用户区主存为 512KB,空闲块链入空闲链表,分配时截取空块的前半部分(小地址部分),初始时全部空闲。

模拟在首次适应算法下,执行如下申请、释放操作序列时,空闲链表和分配链表的变化:reg(300KB)->reg(100KB)->release(300KB)->reg(150KB)->reg(50KB)->reg(90KB)


二、代码实现

linklist.h

#ifndef _LINKLIST_H_
#define _LINKLIST_H_

/**
 * 空闲分区链表和分配分区链表的节点类型定义
 */
typedef struct LNode {
    int m_begin, m_end; // 数据域,分别标识当前节点表示的内存块的起始地址和结束地址
    struct LNode *next; // 指针域
} LNode;

/**
 * 空闲分区链表和分配分区链表的链表类型定义
 */
typedef struct LinkList {
    LNode *m_head; // 头节点
} LinkList;

/**
 * 销毁链表
 * @param list 待操作的链表
 */
void listDestroy(LinkList list) {
    LNode *cur = list.m_head;
    while (cur) {
        LNode *tmp = cur->next;
        free(cur);
        cur = tmp;
    }
}

/**
 * 在指定位置后插入新节点
 * @param pre_node 待插入位置的前序节点
 * @param begin 新节点的起始地址值
 * @param end 新节点的结束地址值
 */
void listInsertByPosition(LNode *pre_node, int begin, int end) {
    LNode *new_node = (LNode *) malloc(sizeof(LNode));
    new_node->m_begin = begin;
    new_node->m_end = end;
    new_node->next = pre_node->next;
    pre_node->next = new_node;
}

/**
 * 根据值插入新节点
 * @param list 待操作的链表
 * @param begin 新节点的起始地址值
 * @param end 新节点的结束地址值
 * @return 分配成功返回true,否则返回false
 */
bool listInsertByValue(LinkList list, int begin, int end) {
    LNode *new_node = (LNode *) malloc(sizeof(LNode));
    new_node->m_begin = begin;
    new_node->m_end = end;

    for (LNode *cur = list.m_head; cur; cur = cur->next) {
        if (cur->next == NULL || cur->next->m_begin >= end) {
            new_node->next = cur->next;
            cur->next = new_node;

            return true;
        }
    }

    return false;
}

/**
 * 删除指定位置后面的节点
 * @param pre_node 待删除的节点的前序节点
 * @return 删除成功返回true,否则返回false
 */
bool listDeleteByPosition(LNode *pre_node) {
    if (!pre_node || !pre_node->next) {
        return false;
    }

    LNode *tmp = pre_node->next;
    pre_node->next = pre_node->next->next;
    free(tmp);

    return true;
}

/**
 * 修改指定节点的值
 * @param node 待操作的节点
 * @param begin 新的起始地址值
 * @param end 新的结束地址值
 */
void listAlter(LNode *node, int begin, int end) {
    node->m_begin = begin;
    node->m_end = end;
}

#endif

free_list.h

#ifndef _FREE_LIST_H_
#define _FREE_LIST_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include "linklist.h"

/**
 * 初始化空闲分区链表
 * @param list 待操作的空闲分区链表
 * @param begin 初始状态下空闲分区的起始位置,即内存空间起始位置
 * @param end 初始状态下空闲分区的结束位置,即内存空间结束位置
 */
void freeListInit(LinkList *list, int begin, int end) {
    list->m_head = (LNode *) malloc(sizeof(LNode));

    LNode *new_node = (LNode *) malloc(sizeof(LNode));
    new_node->m_begin = begin;
    new_node->m_end = end;
    new_node->next = NULL;

    list->m_head->next = new_node;
}

/**
 * 输出空闲链表中的数据
 * @param list 待操作的空闲链表
 */
void freeListShow(LinkList list) {
    LNode *cur = list.m_head->next;
    printf("free_list: [head]->");
    while (cur) {
        printf("[%d, %d]->", cur->m_begin, cur->m_end);
        cur = cur->next;
    }
    printf("NULL\n");
}

#endif

assign_list.h

#ifndef _ASSIGN_LIST_H_
#define _ASSIGN_LIST_H_

#include <stdio.h>
#include <stdlib.h>

#include "linklist.h"

/**
 * 初始化分配分区链表
 * @param list 待操作的分配分区链表
 */
void assignListInit(LinkList *list) {
    list->m_head = (LNode *) malloc(sizeof(LNode));
    list->m_head->next = NULL;
}

/**
 * 输出分配链表中的数据
 * @param list 待操作的分配分区链表
 */
void assignListShow(LinkList list) {
    LNode *cur = list.m_head->next;
    printf("assign_list: [head]->");
    while (cur) {
        printf("[%d, %d]->", cur->m_begin, cur->m_end);
        cur = cur->next;
    }
    printf("NULL\n");
}

/**
 * 根据内存块的首尾地址删除分配内存链表中的节点
 * @param list 待操作的分配分区链表
 * @param begin 待删除的内存块的起始地址
 * @param end 待删除的内存块的结束地址
 * @return 删除成功返回true,否则返回false
 */
bool assignListDeleteByValue(LinkList list, int begin, int end) {
    LNode *cur = list.m_head;

    while (cur->next) {
        if (cur->next->m_begin == begin && cur->next->m_end == end) {
            LNode *tmp = cur->next;
            cur->next = cur->next->next;
            free(tmp);
            return true;
        }
        cur = cur->next;
    }

    return false;
}

#endif

main.c

#include "free_list.h"
#include "assign_list.h"

/**
 * 通过首次适应算法进行内存分配
 * @param free_list 待操作的空闲分区链表
 * @param assign_list 待操作的分配分区链表
 * @param size 进程请求的内存大小
 * @param ret_begin 分配成功时分配的内存块的起始地址
 * @param ret_end 分配成功时分配的内存块的结束地址
 * @return 分配成功返回true,反之返回false
 */
bool FF(LinkList free_list, LinkList assign_list, int size, int *ret_begin, int *ret_end) {
    LNode *cur = free_list.m_head->next;

    while (cur) {
        if (cur->m_end - cur->m_begin >= size) { // 当前分区足够大,可以用于分配
            /* 计算分配内存块的首尾地址 */
            *ret_begin = cur->m_begin; // 首地址是当前空闲块首地址
            *ret_end = cur->m_begin + size; // 尾地址是当前空闲块首地址偏移size个单位后的地址

            /* 如果此空闲块没能全部分配出去,要对剩余空闲空间进行记录,否则直接删除即可 */
            if (*ret_end != cur->m_end) {
                listAlter(cur, *ret_end, cur->m_end);
            } else {
                listDeleteByPosition(cur);
            }

            /* 要为刚刚分配的内存块在分配分区链表中进行标识 */
            if (!listInsertByValue(assign_list, *ret_begin, *ret_end)) {
                printf("listInsertByValue error!");
                exit(1);
            }

            return true;
        }
        cur = cur->next;
    }

    return false;
}

/**
 * 向内存中归还内存块
 * @param free_list 待操作的空闲分区链表
 * @param assign_list 待操作的分配分区链表
 * @param begin 待归还内存块的起始地址
 * @param end 待归还内存块的结束地址
 * @return 归还成功返回true,否则返回false
 */
bool RetSpace(LinkList free_list, LinkList assign_list, int begin, int end) {
    /* 从分配分区链表中将对应节点删除 */
    if (!assignListDeleteByValue(assign_list, begin, end)) {
        printf("assignListDeleteByValue error!");
        exit(1);
    }

    /* 向空闲分区链表中进行插入,插入过程中还要考虑到空闲分区的合并 */
    for (LNode *cur = free_list.m_head; cur; cur = cur->next) {
        if (cur->next == NULL) { // 在末尾插入,此时不存在后相邻
            if (cur->m_end == begin) { // 归还空闲区与前序空闲区相邻
                listAlter(cur, cur->m_begin, end);
            } else { // 不存在相邻
                listInsertByPosition(cur, begin, end);
            }
            return true;
        } else if (cur == free_list.m_head && cur->next->m_begin >= end) { // 在开头插入,此时不存在前相邻
            if (cur->next->m_begin == end) { // 归还空闲区与后序空闲区相邻
                listAlter(cur->next, begin, cur->next->m_end);
            } else { // 不存在相邻
                listInsertByPosition(cur, begin, end);
            }
            return true;
        } else if (cur->next->m_begin >= end) { // 在中间位置插入
            if (cur->m_end != begin && cur->next->m_begin != end) { // 没有相邻,无需合并,直接插入即可
                if (!listInsertByValue(free_list, begin, end)) {
                    printf("listInsertByValue error!");
                    exit(1);
                }
            } else if (cur->m_end == begin && cur->next->m_begin == end) { // 与前后空闲区都相邻,需要进行合并
                /* 这里通过修改前空闲区的结束位置,并删除后空闲区来实现合并,反之亦可 */
                cur->m_end = end;
                if (!listDeleteByPosition(cur)) {
                    printf("listDeleteByPosition error!");
                    exit(1);
                }
            } else { // 存在单相邻
                if (cur->m_end == begin) { // 前相邻
                    listAlter(cur, cur->m_begin, end);
                } else { // 后相邻
                    listAlter(cur, begin, cur->m_end);
                }
            }
            return true;
        }
    }

    return false;
}

int main() {
    LinkList free_list;
    LinkList assign_list;

    int records[5][2]; // 累计会申请五次内存,记录这五块内存的起始地址和结束地址

    /* 初始化两个链表 */
    freeListInit(&free_list, 0, 512);
    assignListInit(&assign_list);

    freeListShow(free_list);
    assignListShow(assign_list);

    /* reg(300KB) */
    printf("----------reg(300KB)----------\n");
    FF(free_list, assign_list, 300, &records[0][0], &records[0][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* reg(100KB) */
    printf("----------reg(100KB)----------\n");
    FF(free_list, assign_list, 100, &records[1][0], &records[1][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* release(300KB) */
    printf("----------release(300KB)----------\n");
    RetSpace(free_list, assign_list, records[0][0], records[0][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* reg(150KB) */
    printf("----------reg(150KB)----------\n");
    FF(free_list, assign_list, 150, &records[2][0], &records[2][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* reg(50KB) */
    printf("----------reg(50KB)----------\n");
    FF(free_list, assign_list, 50, &records[3][0], &records[3][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* reg(90KB) */
    printf("----------reg(90KB)----------\n");
    FF(free_list, assign_list, 90, &records[4][0], &records[4][1]);
    freeListShow(free_list);
    assignListShow(assign_list);

    /* 销毁两个链表 */
    listDestroy(free_list);
    listDestroy(assign_list);

    return 0;
}

三、执行结果

atreus@MacBook-Pro % gcc main.c -o main 
atreus@MacBook-Pro % ./main
free_list: [head]->[0, 512]->NULL
assign_list: [head]->NULL
----------reg(300KB)----------
free_list: [head]->[300, 512]->NULL
assign_list: [head]->[0, 300]->NULL
----------reg(100KB)----------
free_list: [head]->[400, 512]->NULL
assign_list: [head]->[0, 300]->[300, 400]->NULL
----------release(300KB)----------
free_list: [head]->[0, 300]->[400, 512]->NULL
assign_list: [head]->[300, 400]->NULL
----------reg(150KB)----------
free_list: [head]->[150, 300]->[400, 512]->NULL
assign_list: [head]->[0, 150]->[300, 400]->NULL
----------reg(50KB)----------
free_list: [head]->[200, 300]->[400, 512]->NULL
assign_list: [head]->[0, 150]->[150, 200]->[300, 400]->NULL
----------reg(90KB)----------
free_list: [head]->[290, 300]->[400, 512]->NULL
assign_list: [head]->[0, 150]->[150, 200]->[200, 290]->[300, 400]->NULL
atreus@MacBook-Pro % 

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首次适应算法(FIFO算法),也被称为先进先出算法,是一种常见的页面置换算法,主要应用于操作系统中的虚拟内存管理。 在C语言中实现FIFO算法的代码如下: ```c #include <stdio.h> #define MAX_FRAMES 10 // 物理内存帧数 #define MAX_PAGES 50 // 页面数 int main() { int pages[MAX_PAGES]; // 存储页面的数组 int frames[MAX_FRAMES]; // 存储物理内存的数组 int page_faults = 0; // 页面缺失数 int frame_index = 0; // 当前物理内存帧的索引 int page_index = 0; // 当前页面的索引 // 初始化页面数组 for (int i = 0; i < MAX_PAGES; i++) { pages[i] = i % 10; // 页面号为0~9之间循环 } // 初始化物理内存数组 for (int i = 0; i < MAX_FRAMES; i++) { frames[i] = -1; // -1表示该帧为空 } // 开始模拟页面置换过程 while (page_index < MAX_PAGES) { int page = pages[page_index]; // 取出当前页面 int found = 0; // 标记该页面是否已经在物理内存中 // 查找该页面是否已经在物理内存中 for (int i = 0; i < MAX_FRAMES; i++) { if (frames[i] == page) { found = 1; break; } } // 如果该页面不在物理内存中,则将其放入物理内存中 if (!found) { frames[frame_index] = page; frame_index = (frame_index + 1) % MAX_FRAMES; // 轮转到下一个物理内存帧 page_faults++; // 页面缺失数加1 } page_index++; // 处理下一个页面 } printf("总共发生了%d次页面缺失\n", page_faults); return 0; } ``` 在上面的代码中,我们使用两个数组分别存储页面和物理内存,使用一个循环来模拟页面置换过程,每次取出一个页面,查找该页面是否已经在物理内存中,如果不在则将其放入物理内存中。如果物理内存已经满了,则使用FIFO算法选择一个页面进行替换。最后输出页面缺失数即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值