慕課指路:操作系統原理
超有意思一定要動手敲下試試的動態分區分配方式【滑稽】
代碼思路來源學校的慕課給出的代碼,自己敲了一遍進行了億點點改動
不過核心思路沒變,異常處理什么的沒有
一、實驗目的
了解動態分區分配方式中使用的數據結構和分配算法,並進一步加深對動態分區存儲管理方式及其實現過程的理解。
二、實驗要求
(1) 用C語言實現采用首次適應算法的動態分區分配過程alloc()和回收過程free()。空閑分區通過空閑分區鏈來管理;在進行內存分配時,系統優先使用空閑區低端的空間。
(2) 假設初始狀態下,可用的內存空間為640KB,並有下列的請求序列:
-
作業1申請130KB
-
作業2釋放60KB
-
作業3申請100KB
-
作業2釋放60KB
-
作業4申請200KB
-
作業3釋放100KB
-
作業1釋放130KB
-
作業5申請140KB
-
作業6申請60KB
-
作業7申請50KB
-
作業6釋放60KB。
請采用首次適應算法進行內存塊的分配和回收,要求每次分配和回收后顯示出空閑內存分區鏈的情況。
三、實驗內容
1、數據結構
定義請求序列結構體,num代表作業號,state代表該作業申請還是釋放空間,len代表該做也申請或釋放空間的大小。
//定義請求序列結構體
struct Allocquery {
int num;
char state; //a表示申請(apply),f表示釋放(free)
int len; //長度
Allocquery(int n = 0, char s = 'f', int l = 0):num(n), state(s), len(l){}
} alocq[MaxNum];
定義內存分配隊列結構體,flag為0時表示該內存塊空閑,為其他數值則表示相應作業。如為1則表示存儲的是作業1。firstadd表示該內存塊的首地址,len表示該內存塊的大小。
//定義內存分配隊列
struct Freequery {
int flag; //0表示空閑,其他數值表示相應作業
int firstadd; //起始地址
int len; //占有長度
Freequery(int f = 0, int fi = 0, int l = 0) : flag(f), firstadd(fi), len(l) {}
} freeq[MaxNum];
2、初始化
從文件中讀取,in.txt內容為題意要求的作業請求隊列,1 a 130表示作業1申請130KB的空間
1 a 130
2 f 60
3 a 100
2 f 60
4 a 200
3 f 100
1 f 130
5 a 140
6 a 60
7 a 50
6 f 60
定義常量
const string InputFileName = "in.txt";
const string OutputFileName = "out.txt";
const int MaxNum = 11;
首先初始化作業請求序列,利用c++文件流,初始化每個作業請求。
//初始化作業請求序列
void initAlocq() {
ifstream infp(InputFileName, ios::in);
int index = 0;
while(!infp.eof() && index < MaxNum) {
int num;
stringstream ss;
infp >> alocq[index].num >> alocq[index].state >> alocq[index].len;
++index;
}
infp.close();
}
然后初始化內存空間,注意Freequery的構造函數中默認參數中len一開始都為0,也就是說len為0則這個內存塊不存在,可以作為循環結束的依據,所以一開始將freeq[0]的長度置為整個內存空間的長度。
void initFreeq() {
freeq[0].flag = 0, freeq[0].firstadd = 0, freeq[0].len = 640;
}
3、主程序
對每次作業請求執行操作,並顯示執行結果在文件out.txt中。其中Freetotal表示內存空余塊的數量,一開始當然為1,first_alg為首次適應算法,參數為請求塊、當前空塊個數、內存分配隊列 。
void Run() {
ofstream outfp(OutputFileName, ios::out);
int Freetotal = 1;
//對每次作業請求執行操作,顯示執行結果
for(int i = 0; i < MaxNum; ++i ) {
first_alg(alocq[i], Freetotal, freeq);
outfp << "序列" << i+1 << ":作業" << alocq[i].num;
if(alocq[i].state == 'a') outfp << "申請" << alocq[i].len << "K\n";
else outfp << "釋放" << alocq[i].len << "K\n";
outfp << "Now total free blocks:" << Freetotal << endl;
outfp << "IDNum\taddress\t\tlength"<< endl;
for(int j = 0 ; freeq[j].len != 0; ++j) {
outfp << " " << freeq[j].flag << "\t\t "
<< freeq[j].firstadd << "\t\t "
<< freeq[j].len << endl;
}
outfp << "--------------------------------------------------\n" << endl;
}
outfp.close();
}
int main() {
initAlocq();
initFreeq();
Run();
return 0;
}
首次適應算法,參數為請求塊、當前空塊個數、內存分配隊列
函數聲明:
void first_alg(Allocquery nowaloc, int &ptotal, Freequery *pfreeq);
首先判斷是申請空間還是釋放空間,若為申請空間,遍歷所有內存塊。當且僅當該內存塊pfreeq[i]沒有被分配,且大小大於等於申請的空間量,將該塊分配給該作業,並將空塊合並,詳細的合並方法在注釋里都有體現。若為釋放空間,那就找到待釋放的塊將其釋放,並將釋放后空閑區合並。
//首次適應算法
//參數為請求塊、當前空塊個數、內存具體使用情況
void first_alg(Allocquery nowaloc, int &ptotal, Freequery *pfreeq){
Freequery temp;
Freequery temp_f1, temp_f2;
if(nowaloc.state == 'a') {
//申請空間
for(int i = 0; i < MaxNum; ++i) {
//該內存塊空閑 且空間足以分給該作業
if(pfreeq[i].flag == 0 && pfreeq[i].len >= nowaloc.len) {
temp.flag = pfreeq[i].flag;
temp.firstadd = pfreeq[i].firstadd+nowaloc.len; //首地址下移
temp.len = pfreeq[i].len-nowaloc.len; //剩余空間長度
//找到的空塊長度正好等於請求塊,則立刻分配
pfreeq[i].flag = nowaloc.num;
pfreeq[i].len = nowaloc.len;
if(pfreeq[i+1].len == 0) {
//找到的空塊正好是全部剩余空間
pfreeq[i+1] = temp;
} else if (pfreeq[i+1].firstadd != temp.firstadd){
//前后被占用,空塊在中間,且長度大於請求塊
temp_f1 = temp;
temp_f2 = pfreeq[i+1];
int j;
for(j = i+1; pfreeq[j].len != 0; ++j) {
pfreeq[j] = temp_f1;
temp_f1 = temp_f2;
temp_f2 = pfreeq[j+1];
}
pfreeq[j] = temp_f1;
}
break;
}
}
} else {
//釋放空間
for(int i = 0; i < MaxNum; ++i) {
if(pfreeq[i].flag == nowaloc.num) {
//找到待回收的塊
if(i > 0 && pfreeq[i-1].flag == 0 && pfreeq[i+1].flag == 0) {
//前后都為空塊,且回收塊的首地址不是0
pfreeq[i-1].len = pfreeq[i-1].len + nowaloc.len + pfreeq[i+1].len;
for(int j = i; pfreeq[j].len != 0; ++j) {
//三塊合並后隊列變化
pfreeq[j] = pfreeq[j+2];
}
} else if(i > 0 && pfreeq[i-1].flag == 0) {
//前為空塊,后不為空塊,且不是首塊
pfreeq[i-1].len = pfreeq[i-1].len + nowaloc.len;
for(int j = i; pfreeq[j].len != 0; ++j) {
//兩塊合並后隊列變化
pfreeq[j] = pfreeq[j+1];
}
} else if(pfreeq[i+1].flag == 0) {
//后為空塊
pfreeq[i].flag = 0;
pfreeq[i].len = nowaloc.len + pfreeq[i+1].len;
for(int j = i+1; pfreeq[j].len != 0; ++j) {
pfreeq[j] = pfreeq[j+1];
}
} else {
//前后都不空
pfreeq[i].flag = 0;
}
}
}
}
int fnum = 0; //統計空閑塊
for(int i = 0; pfreeq[i].len != 0; ++i)
if(pfreeq[i].flag == 0) ++fnum;
ptotal = fnum;
}
四、實驗結果
五、完整代碼
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
const string InputFileName = "in.txt";
const string OutputFileName = "out.txt";
const int MaxNum = 11;
//定義請求序列結構體
struct Allocquery {
int num;
char state; //a表示申請(apply),f表示釋放(free)
int len; //長度
Allocquery(int n = 0, char s = 'f', int l = 0):num(n), state(s), len(l){}
} alocq[MaxNum];
//定義內存分配隊列
struct Freequery {
int flag; //0表示空閑,其他數值表示相應作業
int firstadd; //起始地址
int len; //占有長度
Freequery(int f = 0, int fi = 0, int l = 0) : flag(f), firstadd(fi), len(l) {}
} freeq[MaxNum];
//首次適應算法
//參數為請求塊、當前空塊個數、內存分配隊列
void first_alg(Allocquery nowaloc, int &ptotal, Freequery *pfreeq);
//初始化作業請求序列
void initAlocq() {
ifstream infp(InputFileName, ios::in);
int index = 0;
while(!infp.eof() && index < MaxNum) {
int num;
stringstream ss;
infp >> alocq[index].num >> alocq[index].state >> alocq[index].len;
//cout << alocq[index].num << ' ' << alocq[index].state << ' ' << alocq[index].len << endl;
++index;
}
infp.close();
}
//初始化內存空間
void initFreeq() {
freeq[0].flag = 0, freeq[0].firstadd = 0, freeq[0].len = 640;
}
void Run() {
ofstream outfp(OutputFileName, ios::out);
int Freetotal = 1;
//對每次作業請求執行操作,顯示執行結果
for(int i = 0; i < MaxNum; ++i ) {
first_alg(alocq[i], Freetotal, freeq);
outfp << "序列" << i+1 << ":作業" << alocq[i].num;
if(alocq[i].state == 'a') outfp << "申請" << alocq[i].len << "K\n";
else outfp << "釋放" << alocq[i].len << "K\n";
outfp << "Now total free blocks:" << Freetotal << endl;
outfp << "IDNum\taddress\t\tlength"<< endl;
for(int j = 0 ; freeq[j].len != 0; ++j) {
outfp << " " << freeq[j].flag << "\t\t "
<< freeq[j].firstadd << "\t\t "
<< freeq[j].len << endl;
}
outfp << "--------------------------------------------------\n" << endl;
}
outfp.close();
}
int main() {
initAlocq();
initFreeq();
Run();
return 0;
}
//首次適應算法
//參數為請求塊、當前空塊個數、內存具體使用情況
void first_alg(Allocquery nowaloc, int &ptotal, Freequery *pfreeq){
Freequery temp;
Freequery temp_f1, temp_f2;
if(nowaloc.state == 'a') {
//申請空間
for(int i = 0; i < MaxNum; ++i) {
//該內存塊空閑 且空間足以分給該作業
if(pfreeq[i].flag == 0 && pfreeq[i].len >= nowaloc.len) {
temp.flag = pfreeq[i].flag;
temp.firstadd = pfreeq[i].firstadd+nowaloc.len; //首地址下移
temp.len = pfreeq[i].len-nowaloc.len; //剩余空間長度
//找到的空塊長度正好等於請求塊,則立刻分配
pfreeq[i].flag = nowaloc.num;
pfreeq[i].len = nowaloc.len;
if(pfreeq[i+1].len == 0) {
//找到的空塊正好是全部剩余空間
pfreeq[i+1] = temp;
} else if (pfreeq[i+1].firstadd != temp.firstadd){
//前后被占用,空塊在中間,且長度大於請求塊
temp_f1 = temp;
temp_f2 = pfreeq[i+1];
int j;
for(j = i+1; pfreeq[j].len != 0; ++j) {
pfreeq[j] = temp_f1;
temp_f1 = temp_f2;
temp_f2 = pfreeq[j+1];
}
pfreeq[j] = temp_f1;
}
break;
}
}
} else {
//釋放空間
for(int i = 0; i < MaxNum; ++i) {
if(pfreeq[i].flag == nowaloc.num) {
//找到待回收的塊
if(i > 0 && pfreeq[i-1].flag == 0 && pfreeq[i+1].flag == 0) {
//前后都為空塊,且回收塊的首地址不是0
pfreeq[i-1].len = pfreeq[i-1].len + nowaloc.len + pfreeq[i+1].len;
for(int j = i; pfreeq[j].len != 0; ++j) {
//三塊合並后隊列變化
pfreeq[j] = pfreeq[j+2];
}
} else if(i > 0 && pfreeq[i-1].flag == 0) {
//前為空塊,后不為空塊,且不是首塊
pfreeq[i-1].len = pfreeq[i-1].len + nowaloc.len;
for(int j = i; pfreeq[j].len != 0; ++j) {
//兩塊合並后隊列變化
pfreeq[j] = pfreeq[j+1];
}
} else if(pfreeq[i+1].flag == 0) {
//后為空塊
pfreeq[i].flag = 0;
pfreeq[i].len = nowaloc.len + pfreeq[i+1].len;
for(int j = i+1; pfreeq[j].len != 0; ++j) {
pfreeq[j] = pfreeq[j+1];
}
} else {
//前后都不空
pfreeq[i].flag = 0;
}
}
}
}
int fnum = 0; //統計空閑塊
for(int i = 0; pfreeq[i].len != 0; ++i)
if(pfreeq[i].flag == 0) ++fnum;
ptotal = fnum;
}