文件系统——空闲块成组链接法的模拟

文章目录

  • 文件系统——空闲块成组链接法的模拟
    • 内容
    • 思路
    • 代码
    • 结果与分析
      • 1. 创建成组链表
      • 2. 分配
          • //申请的盘块数不合理
          • //申请的盘块数不大于超级栈的最大栈深N
        • //申请的盘块数大于超级栈的最大栈深N
        • //分配的空间超出剩余的空间
      • 3. 释放
        • //释放的盘块数大于已分配的数量
        • //释放的盘块数合理,超出了超级栈的剩余存放盘块空间数量
        • // 释放的内容小于当前超级栈剩余的盘块空间
      • 4. 维护盘块
        • //将磁盘乱序的盘块,凑成连续块
    • 另外的补充知识:

内容

  1. 设计合适的数据结构模拟磁盘空闲块的情况。
    (操作系统第二版 孟庆昌 5.4下的第4点)

  2. 模拟分配空闲块的过程。

  3. 模拟回收空闲块的过程。

  4. 模拟对所有空闲块进行分析、凑连续块 的维护过程。

思路

步骤一:

了解知识点:

  1. 空闲块成组链接法的创建和功能

  2. 了解运行的过程和原理

  3. 写出数据结构和程序结构

  4. 运行调试

  5. 补充功能

步骤二:

1. 数据结构:

  • 超级栈s_stack

  • 超级栈深 s_stack.stackDeepth

  • 栈st

  • 栈深 stackDeepth(本次实验为10)

  • 栈头 stack[10]

  • 盘块号 stack[n] int

  • 组长盘块 Captin 栈指针st*

  • 空闲块 :栈内成员 除了第一个组长

  • 申请空间:申请的名称 申请盘块数量 自动分配对应的盘块号,进队

  • 释放空间:释放名称 自动对应相应的数量和盘块号,出队

2. 函数、功能结构:

    1. 构建空闲块成组链接 void makeList()
    1. 分配空闲盘块st* Devide(st* stack,int n)
    1. 释放盘块void Release(st* stack,int n)
    1. 展现当前盘块的状态void showStack(st* stack)
    1. 维护盘块void SafeStack(st* stack)

3. 过程结构:

队列:

  • 分配队入出栈 分配成功的条件:栈减去的长度==队列进来的长度
    当分配到栈底盘块时,先将栈底盘块出栈,将改盘块数据督导超级块栈中,再将超级块的栈顶分配出去

  • 释放队出进栈 释放成功的条件:队列出去的长度==栈增加的长度
    当栈满的时候,若再回收一个盘块,先将栈内数据写到该新回收的盘块中,将栈清空,再将该回收的盘块作为超级栈。

分配过程:
需要新建文件分配空闲盘块,先把超级块中表示栈深的数值减一,加入加一得到39,就以39为索引,检索超级块中的空闲块号栈的索引,得到盘块号111,它就是当前分出去的第1个空闲块。
特殊: 如果栈深是1,还要分配两个盘块,那么栈深减一,结果为0,以0为索引下标,得到盘块150,他是第78号组的组长;然后把150号盘块中的内容,下一组77组中所有的空闲盘块的数量50和各个盘块的块好分别放入超级块的栈深和空闲号块,超级栈中记录了第77组盘块的情况;最后,把150号盘块分配出去。至此,

释放过程: 需要删除文件,它占用3个盘块,块号分别是69、75、87.首先释放69号块,把块号为69放在栈深40所对应的元素,然后栈深加1,变为41.接着释放75号块和87号块。最后,超级快中的栈深的值为43,空闲块号栈中新加入
特殊: 栈满了,还要继续释放盘块,以此盘块为组长号。

步骤三:

  • 实验准备:
    准备创建30个空闲块,每个组有10个盘块(栈深是10).
    栈内存储的是盘块号,每个栈的栈底为stack[0],栈顶是stack[9],操作都在栈顶
    第1组的总块数是10,而首块块号标志为0,并不表示物理块号,而是分配警戒位,作为空闲盘块连的结束标志。

代码

数据结构定义

#include<iostream>
#include<queue>
using namespace std;#define N 10 //最大栈深
#define max 30//最大盘块数//普通栈定义
struct st
{int stackDeepth=0; //栈深int stack[N]; //栈头数组 根据栈深获取对应的盘块st* next=NULL; //如果该栈满了 则需要新增一个新栈
};st s_stack; //超级栈   超级栈的栈深s_stack.stackDeepth==s_stackDeepth//初始化栈
void InitStack(st* Stack){Stack->next=NULL;for(int i=0;i<N;i++)Stack->stack[i]=0;Stack->stackDeepth=0;
}
//清空化栈
void CleanStack(st* Stack){Stack->next=NULL;for(int i=0;i<N;i++)Stack->stack[i]=0;Stack->stackDeepth=0;
}
//显示栈表
void showStack(st* stack)
{int n=0;cout<<"*******第0号栈是超级栈*******"<<endl;while(stack!=NULL){//第0号栈是超级栈cout<<"第"<<n<<"个栈的盘块号,栈深是"<< stack->stackDeepth<<endl;for(int i=0;i<N;i++)cout<<"盘块"<<stack->stack[i]<<" ";cout<<endl;if(stack->next!=NULL)stack=stack->next;elsestack=NULL;n++;}
}

//
创建成组链接

//创建成组链接
void makeList()
{int i,a=9;int n;st* tempStack=new st();//定义一个临时的栈 为后续的增加栈准备st* Captain=new st(); //定义一个临时指针for(i=1,n=9;i<max+1;i++){//先填满超级栈,再填普通的栈if(i<N&&n>-1){s_stack.stack[n]=i; //填入盘块号s_stack.stackDeepth++; //栈深+1n--;}else if(i==N) //i==最大栈深的时候 不用最大号盘来存储 而是作为组长块 {s_stack.next=tempStack; //指向下一个栈 下一个栈的名字就是stack[0]s_stack.stackDeepth++; //栈深+1s_stack.stack[0]=i; //栈底的元素是组长,需要置数}else{//这里存放的是普通栈的内容tempStack->stack[a]=i;tempStack->stackDeepth++;a--;if(i%N==0){a=9; //重置一下原来临时栈的栈深盘号if(i==N) //10特殊 是和超级栈相连的{s_stack.next=tempStack; //这里存储的是 地址为0的组Captain=tempStack; //临时将新栈的指针存放在Cap中 这个栈是超级栈后面的第一组if(i!=max)Captain->stack[0]=i; //栈底的元素是组长,需要置数elseCaptain->stack[0]=0; //最后一块栈如果满了,栈底盘块号是0 用来警醒内存满了tempStack=(st*)malloc(sizeof(st)); //分配一个新地址 新栈地址为1(假设)InitStack(tempStack);}else{Captain->next=tempStack; //这里存储的是 地址为1的组Captain=tempStack; //更新Captain指向地址为1的组,这些都是超级栈后面的二、三、四、、、组 if(i!=max)Captain->stack[0]=i; //栈底的元素是组长,需要置数elseCaptain->stack[0]=0; //最后一块栈如果满了,栈底盘块号是0 用来警醒内存满了tempStack=(st*)malloc(sizeof(st)); //分配一个新地址 新栈地址为2(假设) 后面以此类推InitStack(tempStack);}}else //栈不满的情况下{Captain->next=tempStack; //这里存储的是 地址为1的组}}}cout<<"-------开始创建空闲块成组链接------"<<endl;showStack(&s_stack);cout<<"-------创建完成------"<<endl;
}

//
分配磁盘

queue<int> q;   //创建一个int类型的队列q
//分配磁盘
st* Devide(st* stack,int n) //根据数量,减去相应的栈深,以栈深为引,分配相应的磁盘
{int nm=0;st* temp=stack;//判断盘块数是否合理if(n<=0){cout<<"*******************申请的盘块数不合理******************* "<<endl;cout<<endl; return stack;   }//判断是否足够盘块while(temp!=NULL){nm+=temp->stackDeepth;temp=temp->next;}if(n>nm){cout<<"*******************申请的盘块大于剩余盘块,当前剩余盘数为 "<<nm<<" *******************"<<endl;cout<<endl;return stack;}int j=stack->stackDeepth;int tmp;cout<<"-------查看已经分配的磁盘号:"<<endl;//从栈顶开始将分配出去的磁盘号入队for(int i=0;i<n;i++){tmp=j-(i%N)-1;cout<<stack->stack[tmp]<<" ";//队列操作 进队q.push(stack->stack[tmp]);//栈操作 深度减一 清空stack->stackDeepth--;stack->stack[tmp]=0;//tmp==0说明该栈已经分配完了if(tmp==0){n=n-i-1;i=-1;stack=stack->next;//指向下一个栈j=stack->stackDeepth; //获取该栈的栈深}} if(!q.empty()) //判断队列是否空{ cout<<endl; cout<<"数列非空"<<endl;  cout<<"数列q有"<<q.size()<<"个元素"<<endl;  }return stack;
}

//
释放磁盘

void Release(st* stack,int n)//根据数量,增加相应的栈深,以栈深为引,将相应的磁盘号加入栈中
{//先判断此时要释放的盘块是否与已分配的盘块相符if(n>q.size()){cout<<"*******************释放的盘块过多,不合理.**********************"<<endl;cout<<endl;return;}int j=stack->stackDeepth;int tmp;int m1=n-1;//操作数组的变量cout<<"-------查看已经释放的磁盘号:"<<endl;int t[n];//存储从队里面出来的元素for(int m=0;m<n;m++){t[m]=q.front();// 首元素//队列操作 出队 删除首元素q.pop();}//从栈顶开始将分配出去的磁盘号入队for(int i=0;i<n,m1>=0;i++){tmp=j+(i%N);//注意:要大的磁盘号先进栈,小的盘号后进栈//栈操作 进栈 深度加一//cout<<"------m1------"<<m1<<endl;stack->stack[tmp]=t[m1];stack->stackDeepth++;m1--;cout<<stack->stack[tmp]<<" ";//tmp==N-1说明该栈已满if(tmp==N-1){n=n-i;//去掉刚刚已经进栈的i=-1;//循环有个i++ 所以本来要令i=0 还要减一st* tempStack=new st();//分配一个新地址的栈 InitStack(tempStack);//将当前栈的内容存放到新建的临时栈中tempStack->next=stack->next;for(int m=0;m<N;m++){tempStack->stack[m]=stack->stack[m];}tempStack->stackDeepth=stack->stackDeepth;CleanStack(stack);//清空原来的栈(一般操作的都是超级栈)stack->next=tempStack; //指向新的栈j=stack->stackDeepth; //获取栈的栈深}}   if(!q.empty()) //判断队列是否空  {  cout<<endl;cout<<"数列非空"<<endl;  cout<<"数列q有"<<q.size()<<"个元素"<<endl;  }}

//
维护过程

//维护链表(栈内凑连续块) bubble
void SafeStack(st* stack)
{int temp;while (stack!= NULL){for (int i = 0; i < N; i++){for (int j = 0; j < N - i; j++){if (stack->stack[j] < stack->stack[j + 1]){if(stack->stack[0]==0)continue;temp = stack->stack[j];stack->stack[j] = stack->stack[j + 1];stack->stack[j + 1] = temp;}}}stack = stack->next;}
}

//
主函数

int main()
{st* b;//创建成组链表makeList();//A分配0个或-1个盘块,没有超出栈深的分配cout<<endl;b=Devide(&s_stack,0);b=Devide(b,-1);showStack(b);//A分配5个盘块,没有超出栈深的分配cout<<endl;b=Devide(b,5);showStack(b);//A分配7个盘块,超出了栈深的分配cout<<endl;b=Devide(b,7);showStack(b);//A释放13个盘块,超出了已分配的盘块数量,没有那么多盘块可以释放,会失败cout<<endl;Release(b,13);showStack(b);//A释放11个盘块,正常释放cout<<endl;Release(b,11);showStack(b);//B分配7个盘块,在A已经分配的基础上,继续分配cout<<endl;b=Devide(b,7);showStack(b);//B释放两个盘块cout<<endl;Release(b,2);showStack(b);//A释放两个盘块cout<<endl;Release(b,2);showStack(b);//维护盘块 cout<<endl;cout<<"--------维护盘块----------"<<endl;SafeStack(b);showStack(b);//分配的空间超出剩余的空间//B分配30个空间cout<<endl;b=Devide(b,30);showStack(b);return 0;
}

结果与分析

实验结果是有针对性的,对于功能各种极限情况进行测试。

运行主函数,根据得到的结果来分析:

1. 创建成组链表

makeList();

运行结果:

分析:

创建的第0个栈是超级栈,分配和释放的操作都首先在超级栈实现。盘块10到盘块1,是盘块号,从左往右即从stack[0]栈底到stack[9]栈顶。

创建过程是从超级栈的stack[9]开始,当超级栈满了,即超过了数组最大的范围N(本次实验的最大栈深是10),则创建新的栈继续存放,并把当前栈的指针next指向新的栈。

当这个成组链接的最大空间是max==30,则第30个盘块号为0,即上图黑框内容。并不表示物理块号,而是分配警戒位,作为空闲盘块连的结束标志。

2. 分配

//申请的盘块数不合理
    //A分配0个或-1个盘块,没有超出栈深的分配cout<<endl;b=Devide(&s_stack,0);b=Devide(b,-1);showStack(b);

运行结果:

分析:

当申请的盘块数是0或者小于0,则为申请不合理。栈链接无变化。

//申请的盘块数不大于超级栈的最大栈深N
    //A分配5个盘块,没有超出栈深的分配cout<<endl;b=Devide(b,5);showStack(b);

运行结果:

分析:

从栈顶开始取出盘块,放进队列中,队列先进去的是1,接着是2,3,4,5.取出之后,原来盘块号置为0,这个地方有待优化,不能和结束标志相同。
超级栈的栈深变为5,数列q中有5个元素。

//申请的盘块数大于超级栈的最大栈深N
//A分配7个盘块,超出了栈深的分配cout<<endl;b=Devide(b,7);showStack(b);

运行结果:

分析:

根据上一次分配了5个盘块的结果,超级栈的栈深变为5,小于现在所需要的7个盘块,则需要从下一个栈中补上所需要的盘块数。

可以看到原来的超级栈中5个被分配出去,已经空了,则超级栈中存入下一个栈的内容,下一个栈空间释放。继续分配2个盘块11号和12号。

最后栈链接如上图所示,超级栈的栈深是8,数列q有12个元素,本次分配了6,7,8,9,10,11,12号。

//分配的空间超出剩余的空间
    //B分配30个空间cout<<endl;b=Devide(b,30);showStack(b);

运行结果:


分析:

当申请所需的盘块数大于栈链接所剩余的盘块数时,则会提示错误。

实现方法如图所示:

3. 释放

//释放的盘块数大于已分配的数量
//A释放13个盘块,超出了已分配的盘块数量,没有那么多盘块可以释放,会失败cout<<endl;Release(b,13);showStack(b);

运行结果:

分析:

上图黑色框的是代码运行结果。A进程只是申请了12个盘块,没办法释放13个盘块。所以栈链接没有变化,和上一次结果相同。

实现代码:判断释放盘块数n是否大于数列q里的元素数量。

//释放的盘块数合理,超出了超级栈的剩余存放盘块空间数量
//A释放11个盘块,正常释放cout<<endl;Release(b,11);showStack(b);

运行结果:

分析:

上图中,第一个栈链接只有两个栈,在A进程释放了11个盘块之后,栈链接多了一个栈,是因为所释放的盘块数和超级栈中原来剩下的盘块数之和大于超级栈的最大栈深N.出现这种情况的时候,会创建多一个栈空间,将当前超级栈的内容放进新栈之中。

之后新来的盘块则是新栈的组长,这个组长盘块会存放在超级栈之中,超级栈的指针next会指向新建的栈,新栈的next指针内容会继承超级栈原来的指针内容。接着继续往超级栈中存放剩余的释放出来的盘块。

实验结果可以看出,原来超级栈的栈深是8,存入2个盘块之后,栈满,则新建一个栈(组长号是超级栈的srack[0]),新栈的栈深是10,超级栈的栈深为0.接着超级栈继续存放剩下9个盘块,超级栈的栈深变为9,数列q的元素剩余1个(这里仅有A进程的操作,没有进行B进程的操作,所以数列由12-11==1,变为1个元素)。

// 释放的内容小于当前超级栈剩余的盘块空间
//B释放两个盘块cout<<endl;Release(b,2);showStack(b);//A释放两个盘块cout<<endl;Release(b,2);showStack(b);

运行结果:

分析:

在当前超级栈的空余空间大于释放盘块数时,直接将数列列头的元素取出,栈中存在盘块号大的在盘块号小的上面的问题,所以需要维护。

另外,在申请的盘块数合理的前提下,本次实验不存在释放的盘块数大于栈链接最大盘块空间的问题。

4. 维护盘块

//将磁盘乱序的盘块,凑成连续块
 SafeStack(b);

运行结果:

分析:

盘块在释放和分配的过程中,必定会尝试不连续的盘块号,例如上图中第一个框框所示。我是用排序算法将盘块号按栈顶比栈底小的顺序排列。

目前实现的算法的缺陷是,只能在本栈内排序,两个栈之间的算法还没能够实现,这可以是未来改进的地方。

另外的补充知识:

指针用法详情:link
https://www.cnblogs.com/tongye/p/9650573.html

C++简单队列结构:link
https://blog.csdn.net/hao_ge_666/article/details/96481046

文件系统——空闲块成组链接法的模拟相关推荐

  1. 操作系统:文件系统——空闲块成组链接法的模拟

    题目 文件系统--空闲块成组链接法的模拟 (1)设计合适的数据结构模拟磁盘空闲块的情况. (2)模拟分配空闲块的过程. (3)模拟回收空闲块的过程. (4)模拟对所有空闲块进行分析.凑连续块 的维护过 ...

  2. 操作系统之文件系统:4、文件存储空间管理(空闲表法、空闲链表法、位示图法、成组链接法)

    4.文件存储空间管理 思维导图 文件的初始化和划分 文件存储空间管理方法 1.存储空间管理--空闲表法 2.存储空间管理--空闲链表法 3.存储空间管理--位示图法 4.存储空间管理--成组链接法 思 ...

  3. 【操作系统】成组链接法详解

    成组链接法介绍 计算机上的文件是记录在磁盘上的,而磁盘空间的分配是以盘块为单位的,那么如何管理磁盘中已经被使用的块和未被使用的块是操作系统必须要考虑的问题.下面将介绍比较实用又有点复杂的成组链接法,看 ...

  4. 操作系统–––成组链接法

    成组链接法介绍 看不懂打死我 计算机上的文件是记录在磁盘上的,而磁盘空间的分配是以盘块为单位的,那么如何管理磁盘中已经被使用的块和未被使用的块是操作系统必须要考虑的问题.下面将介绍比较实用又有点复杂的 ...

  5. 成组链接法 恩赐解脱

    成组链接法  即空闲表和空闲链里两种方法相结合. 将空闲块按100块为一组进行组织,利用空闲块每组的第0块来存放前一组的100块的地址,所以第0块既是可以分配的空闲块,同时也充当了数据结构. 具体来说 ...

  6. 操作系统成组链接法(@王道论坛)

    操作系统成组链接法

  7. java成组链接法的实现_c++磁盘存储空间的管理模拟(UNIX存储管理的成组链接法的设计与实现)...

    [c++]代码库#include #include #include const int MAXGROUP=10;//定义组的大小 const int MAXJOB=100;//定义一个作业最大能申请 ...

  8. 2022-6-21OS复习成组链接法

    https://blog.csdn.net/smartab/article/details/81285353 https://www.bilibili.com/video/BV1HE41167kj?s ...

  9. 位示图 c语言程序,位示图模拟文件系统空闲快管理c语言

    用数组表示位示图,其中的每一位对应磁盘一个物理块的状态,0表示空闲,1表示分配;当请求分配一个磁盘块时,寻找到数组中为0的位,计算相对磁盘块号,并计算其在磁盘中的物理地址(柱面号.磁道号.物理块号), ...

最新文章

  1. java实现验证码输出_java实现验证码
  2. 【代码笔记】iOS-评分,支持我们
  3. 【Centos】更新为北京时间
  4. SAP Spartacus的User明细如何通过ngrx-store-devtools被解析出来
  5. WM的Image格式分析
  6. 计算机管理用户和组无法访问,同一工作组无法访问如何解决【详解】
  7. 服务器虚拟化底层系统安装,Hyper-V是底层的虚拟机程序,位于操作系统和硬件之间,很薄一层...
  8. 一起学习linux之lamp脚本
  9. 2.17_knight_tour_骑士周游问题 (深度优先 DFS)
  10. sql between的用法的意思_SQL 宝典——SQL 语法速成手册
  11. Android瀑布流照片墙实现,体验不规则排列的美感
  12. 第三季-第21课-多线程同步
  13. linux基础之软件包管理
  14. 电子游戏理论基础初探
  15. 王道训练营3月27日
  16. PPT 各行各业素材 10000套 讲解
  17. ps时间轴制作渐隐动态签名
  18. 软件是指示计算机运行所需的程序,计算机基础知识A.ppt
  19. 淘客订单检测接口--检测淘宝订单是否是淘客订单的接口
  20. 毛玻璃,磨砂玻璃材质,shader笔记

热门文章

  1. [html5]离线存储
  2. 【报表设计】--层次坐标和父子格设置
  3. 网络精英赛模拟练习(7)
  4. cmstop php,CmsTop是什么
  5. 理解:商业模式探索 - 概念基础篇(附思维导图)
  6. Windows网络命令ipconfig详解
  7. 光伏电站融资租赁初具规模
  8. arXiv | Per-FedAvg:一种联邦元学习方法
  9. 大气采样器的结构介绍
  10. 尬聊器(伪聊天机器人)