C 语言模拟首次适应算法

  • Post author:
  • Post category:其他




一、题目描述

某操作系统采用段式管理,用户区主存为

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 % 

在这里插入图片描述



版权声明:本文为qq_43686863原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。