Linux作業系統課程設計
作業系統課程設計
一、課程設計要求
1、按時參加上機實習,不得曠課、遲到、早退。
2、每個學生需在 Linux 下用 C 語言完成六道上機實習題。
3、每個學生需獨立完成上機實習,不得相互抄襲。如發現抄襲者和被抄襲者成績均不及格。
4、每個學生需在實習結束一週內將實習報告和源程式提交到班級 學習委員,再由學習委員打包發到老師的郵箱,用於檢查是否存在抄襲 現象,郵件中請註明學生的班級和姓名。
5、每個學生需在實習結束一週內提交紙質實習報告一份。應包括如 下內容: 1)課程設計題目 2)程式功能及設計思路 3)資料結構及演算法設計 4)程式執行情況 5)程式設計中遇到的困難及解決方法、實習心得或良好建議
二、 評分
1、考勤佔 20%,上機驗收佔 40%,實習報告佔 40%。
2、抄襲程式者和被抄襲程式者,課程設計成績不及格。
3、抄襲報告者和被抄襲報告者,課程設計成績不及格。前六次上機每次完成一道實習題,最後兩次上機組織驗收。
三、上機時間地點
17 周 (12 月 25-29 日)週二下午 週四下午 週五上午 晚上
18 周 (元月 1-5 日)週二下午 週三下午 晚上
前 7 次地點:12 班在 313 機房(Fedora) 34 班在 413 機房(Ubuntu)
最後一次上機: 12 班:18 週週四 晚上 34 班:18 週週五 晚上
地點:313 機房(Fedora) 上午 8:30-11:30 下午 2:00-5:00 晚上 6:30-9:30
開機時進入 Linux 系統,預設使用使用者名稱:suer,密碼:123456。若預設密碼登入不了,可能是被同學修改過了,換一臺電腦使用。請同學們千萬不要修改系統登入密碼。若有同學自己的膝上型電腦已經裝了 Linux,歡迎自帶電腦上機實習。
四、每次上機實習前先自學預備知識,並在作業本上編寫初步的源程式。
五、課程設計題目課程設計分六個實驗,具體如下:
實驗 1:作業排程
1.1實驗目的
1、 對作業排程的相關內容作進一步的理解。
2、 明白作業排程的主要任務。
3、 通過程式設計掌握作業排程的主要演算法。
1.2實驗內容
1、假設系統中可同時執行兩道作業,給出每道作業的到達時間和執行時間,如下表所示:
作業名 |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
到達時間 |
0 |
2 |
5 |
7 |
12 |
15 |
4 |
6 |
8 |
10 |
執行時間 |
10 |
20 |
30 |
40 |
8 |
8 |
20 |
10 |
12 |
7 |
2、分別用先來先服務演算法、短作業優先和響應比高者優先三種演算法給出作業的排程順序。
3、計算每一種演算法的平均週轉時間及平均帶權週轉時間並比較不同演算法的優劣。
1.3預備知識:
響應比=等待時間/執行時間+1
週轉時間=完成時間-到達時間 帶權週轉時間=週轉時間/執行時間
實驗 2:磁碟排程
2.1實驗目的
1、對磁碟排程的相關知識作進一步的瞭解,明確磁碟排程的原理。
2、加深理解磁碟排程的主要任務。
3、通過程式設計,掌握磁碟排程的主要演算法。
2.2實驗內容
1、對於如下給定的一組磁碟訪問進行排程:
請求服務到達 |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
訪問的磁軌號 |
50 |
100 |
180 |
20 |
90 |
150 |
70 |
80 |
101 |
60 |
120 |
40 |
110 |
30 |
2、要求分別採用先來先服務、最短尋道優先以及電梯排程演算法進行排程。
3、要求給出每種演算法中磁碟訪問的順序,計算出平均移動道數。
4、假定當前讀寫頭在 90 號,向磁軌號增加的方向移動。
實驗 3:熟悉 linux 檔案系統呼叫
3.1實驗目的
1.掌握 linux 提供的檔案系統呼叫的使用方法;
2.熟悉檔案系統的系統呼叫使用者介面;
3.瞭解作業系統檔案系統的工作原理和工作方式。
3.2實驗內容
使用檔案系統呼叫編寫一個檔案工具 filetools,使其具 有以下功能:
1.建立新檔案 2.寫檔案 3.讀檔案 4.修改檔案許可權 5.檢視當前檔案許可權 0.退出
提示使用者輸入功能號,並根據使用者輸入的功能選擇相應的功能。 檔案按可變記錄檔案組織,具體記錄內容自行設計。
3.3預備知識:
使用者在針對檔案進行操作之前時一定要先開啟它,這是由於系統需要根據使用者提供的引數來查詢檔案 的目錄項,並由目錄項找到檔案的磁碟 i 結點,再將它調到記憶體 i 結點,才能建立使用者程序與該檔案之間的聯絡。
同樣,在檔案操作完畢後要關閉檔案,以切斷使用者程序與檔案的聯絡,釋放相關資源。
Open 系統呼叫
int open(const char *path, int flags);
int open(const char *path, int flags,mode_t mode);
一般情況下使用兩個引數的格式,只有當開啟的檔案不存在時才使用 3 個引數的格式。引數:
Path 指向所要開啟的檔案的路徑名指標。
Flag 標誌引數,用來規定開啟方式,必須包含以下 3 個之一:
O_RDONLY 只讀方式
O_WRONLY 只寫方式
O_RDWR 讀寫方式
利用按位邏輯或“|”對下列標誌進行任意組合:
O_CREAT 如果檔案不存在則建立該檔案,若存在則忽略。
O_TRUNC 如果檔案存在則將檔案長度截為 0,屬性和所有者不變。
C_EXECL 如果檔案存在且O_CREAT 被設定則強制 open 呼叫失敗。
O_APPEND 每次寫入時都從檔案尾部開始。
Mode 是檔案的訪問許可權,分為檔案所有者、檔案使用者組和其他使用者。
Close 系統呼叫
對於一個程序來說可以同時開啟的檔案是有限的,為了使檔案識別符號能夠及時釋放,系統必須提供關閉檔案操作。
Int close(int fd)
Fd 為開啟檔案時系統返回的檔案識別符號
系統執行該系統呼叫時,根據 fd 值在該程序的程序開啟檔案表中找到 fd 標識,根據指標找到系統開啟 檔案表,再找到記憶體i 結點表中相應的 i 結點,對其i_count 進行減1 操作, 然後釋放系統開啟檔案表中的表項和程序開啟檔案表的表項。
結果:呼叫成功返回 0
實驗 4:程序管理
4.1實驗目的
1. 理解程序的概念,明確程序和程式的區別。
2. 理解併發執行的實質。
3. 掌握程序的同步、撤銷等程序控制方法。
4.2實驗內容
父程序使用系統呼叫pipe()建立一個管道,然後使用系統呼叫fork()建立兩個子程序:子程序1和子程序2
子程序1每隔1秒通過管道向子程序2傳送資料:I send message x times.(x 初值為1,以後傳送一 次後做加一操作)子程序 2 從管道讀出資訊,並顯示在螢幕上
父程序用系統呼叫 signal()來捕捉來自鍵盤的中斷訊號(即按Ctrl+C 鍵);當捕捉到中斷訊號後,父程序用系統呼叫kill()向兩個子程序發出訊號,子程序捕捉到訊號後分別輸出如下資訊後終止: Child Process 1 is killed by Parent! Child Process 2 is killed by Parent!
父程序等待兩個子程序終止後,釋放管道並輸出如下的資訊後終止 Parent Process is Killed!
實驗 5:請求分頁系統中的置換演算法
5.1實驗目的
1. 瞭解虛擬儲存技術的特點;
2. 掌握請求分頁系統的頁面置換演算法。
5.2實驗內容
1.通過如下方法產生一指令序列,共 320 條指令。
A. 在[0,319]的指令地址之間隨機選取一起點 M;
B. 順序執行一條指令,即執行地址為 M+1 的指令;
C. 在前地址[0,M+1]中隨機選取一條指令並執行,該指令的地址為 M1;
D. 順序執行一條指令,其地址為 M1+1;
E. 在後地址[M1+2,319]中隨機選取一條指令並執行,該指令的地址為 M2;
F. 順序執行一條指令,其地址為 M2+1;
G. 重複A—F,直到執行 320 次指令。
2. 指令序列變換成頁地址流,設 :
(1)頁面大小為1K;
(2) 使用者記憶體容量為 4 頁到 32 頁,步長為 1;
(3)使用者虛存容量為 32K。 在使用者虛存中,按每頁存放10 條指令排列虛存地址,即 320 條指令在虛存中的存放方式為: 第0條—第9條指令為第0頁(對應虛存地址為[0,9]);第10條—第19條指令為第1頁(對應虛存地址為[10,19]) ; …………………… 第310條—第319條指令為第31頁(對應虛存地址為[310,319]) ;
按以上方式,使用者指令可組成 32 頁。
3. 計算並輸出下述各種演算法在不同記憶體容量下的命中率。
A. 先進先出(FIFO)頁面置換演算法
B. 最近最久未使用(LRU)頁面置換演算法--最近最少使用演算法
C. 最佳(Optimal)頁面置換演算法
實驗 6:程序通訊
6.1實驗目的
1. 理解管道機制、訊息緩衝佇列、共享儲存區機制進行程序間的通訊;
2. 理解通訊機制。
6.2實驗內容
編寫一主程式可以由使用者選擇如下三種程序通訊方式:
1. 使用管道來實現父子程序之間的程序通訊:子程序向父程序傳送自己的程序識別符號,以及字串“is sending a message to parent”。父程序則通過管道讀出子程序發來的訊息,將訊息顯示在螢幕上,然後終止。
2. 使用訊息緩衝佇列來實現 client 程序和server 程序之間的通訊:server 程序先建立一個關鍵字為 SVKEY(如75)的訊息佇列,然後等待接收型別為 REQ (例如 1)的訊息;在收到請求訊息後,它便顯示字串“serving for client”和接收到的 client 程序的程序標識數,表示正在為 client 程序服務;然後再向 client 程序傳送應答訊息, 該訊息的型別是 client 程序的程序標識數,而正文則是 server 程序自己的標識 ID。client 程序則向訊息佇列傳送型別為 REQ 的訊息(訊息的正文為自己的程序標識 ID) 以取 得 sever 程序的服務,並等待server 程序發來的應答;然後顯示字串“receive reply from”和接收到的 server 程序的標識 ID。
3. 使用共享儲存區來實現兩個程序之間的程序通訊:程序 A 建立一個長度為 512 位元組的共享記憶體,並顯示寫入該共享記憶體的資料;程序 B 將共 享記憶體附加到自己的地址空間,並向共享記憶體中寫入資料。
六、實驗報告+原始碼下載地址
七、實驗五報告程式碼
#include<iostream>
#include<ctime>
#include<stdlib.h>
using namespace std;
int N = 3;//記憶體
int Process[320];//頁面佇列
int Memory[32];//塊數
int OPTQueue[320];//OPT演算法的佇列
int FIFOQueue[320];//FIFO演算法佇列
int LRUQueue[320];//LRU演算法佇列
int ttime[320];//設定的一個時間標誌,FIFO演算法時判斷哪個是最先進來的
int flag[320];//設定一個標誌,LUR演算法判斷哪個是最近最久未使用的
int ProcessNum;//頁面數
int id[320];//320個程序序列
int address[320];//zhilingzidian
int Size = 0;
int Randf(int l, int r) { return (rand() % (r - l + 1) + l); }
void CreateProcess()
{
srand(static_cast<unsigned>(time(NULL)));
Size = 0;
for (int i = 0;i < 64;++i)
{
int m = Randf(0, 319);
id[Size++] = m + 1;
m = Randf(0, m + 1);
id[Size++] = m;
id[Size++] = m + 1;
m = Randf(m + 2, 319);
id[Size++] = m;
id[Size++] = m + 1;
}
cout << "指令序列:" << endl;
for (int i = 0;i < Size;++i)
cout << id[i] << " ";
cout << endl;
}
//OPT演算法找到最長未使用的
int longest(int start)
{
int i;
int count[320];
for (int i = 0;i < 320;++i)
count[i] = 0;
for (int j = 0;j < N;++j)
{
for (i = start + 1;i < ProcessNum;i++)
{
if (Memory[j] != OPTQueue[i])
count[j]++;
if (Memory[j] == OPTQueue[i])
break;
}
}
int ti = -1, mmax = -1;
for (int i = 0;i < N;++i)
{
if (mmax < Memory[i])
{
mmax = Memory[i];
ti = i;
}
}
return ti;
}
//OPT 演算法
void OPT()
{
int i, j, k;
int num = N;
for (i = 0;i < ProcessNum;i++)
{
OPTQueue[i] = Process[i];
}
for (i = 0;i < N;i++)
{
Memory[i] = OPTQueue[i];
}
for (i = N;i < ProcessNum; ++i)
{
for (j = 0;j < N;j++)
{
if (Memory[j] == OPTQueue[i])
break;
}
if (j == N)
{
k = longest(i);
Memory[k] = OPTQueue[i];
num++;
}
}
cout << "命中次數:" << ProcessNum - num << endl;
float str;
str = (float)(ProcessNum - num) / ProcessNum;
cout << "命中率=" << str * 100 << "%" << endl;
}
//FIFO演算法找到最早進來的那個
int MaxTime()
{
int ti = -1, mmin = 100000;
for (int i = 0;i<N;++i)
{
if (mmin > ttime[i])
{
mmin = ttime[i];
ti = i;
}
}
return ti;
}
//FIFO演算法
void FIFO()
{
int i, j, k;
int num = N;
for (i = 0;i<ProcessNum;i++)
{
FIFOQueue[i] = Process[i];
}
for (i = 0;i<N;i++)
{
Memory[i] = FIFOQueue[i];
ttime[i] = i;
}
for (i = N;i<ProcessNum;i++)
{
for (j = 0;j<N;j++)
{
if (Memory[j] == FIFOQueue[i])
break;
}
if (j == N)
{
k = MaxTime();
ttime[k] = i;
Memory[k] = FIFOQueue[i];
num++;
}
}
cout << "命中次數:" << ProcessNum - num << endl;
float str;
str = (float)(ProcessNum - num) / ProcessNum;
cout << "命中率=" << str * 100 << "%" << endl;
}
//LRU演算法找到最近最久未使用的
int MinFlag()
{
int ti = -1, mmin = 100000;
for (int i = 0;i < N;++i)
{
if (mmin > flag[i])
{
mmin = flag[i];
ti = i;
}
}
return ti;
}
//LRU演算法
void LRU()
{
int i, j, k;
int num = N;
for (i = 0;i<ProcessNum;i++)
{
LRUQueue[i] = Process[i];
}
for (i = 0;i<N;i++)
{
Memory[i] = LRUQueue[i];
flag[i] = i;
}
for (i = N;i<ProcessNum;i++)
{
for (j = 0;j<N;j++)
{
if (Memory[j] == LRUQueue[i])
{
flag[j] = i;
break;
}
}
if (j == N)
{
k = MinFlag();
flag[k] = i;
Memory[k] = LRUQueue[i];
num++;
}
}
cout << "命中次數:" << ProcessNum - num << endl;
float str;
str = (float)(ProcessNum - num) / ProcessNum;
cout << "命中率=" << str * 100 << "%" << endl;
}
int main()
{
int i;
while (N != 0) {
cout << "-------------------頁面置換演算法-------------------------" << endl;
cout << "程序數:320" << endl;
ProcessNum = 320;
CreateProcess();//生成320個指令序列
cout << "指令序列生成完畢" << endl << endl;
for (i = 0;i < ProcessNum; ++i)
Process[i] = id[i] / 10;
N = 4;
while (N != 1 && N != 0) {
cout << "請輸入記憶體容量:[4-32]\n1 for 重新生成指令序列\n0 for 退出程式" << endl;
cin >> N;
if (N == 0 || N == 1)
break;
cout << "OPT最佳置換演算法" << endl;
OPT();
cout << endl;
cout << "FIFO先進先出頁面置換演算法" << endl;
FIFO();
cout << endl;
cout << "LRU最近最久未使用置換演算法" << endl;
LRU();
cout << endl;
}
}
return 0;
}