第一篇:操作系統進程管理系統設計實驗報告
實驗報告說明書
設計名稱: 操作系統課程設計
實 驗 : 進程調度設計
學生姓名:
專 業: 網絡工程 班 級: 08級一班 學 號:
指導教師:雷曉平王東 黃營 楊躍武 日 期: 2011年 6月 19日
課程設計任務書
網絡工程 專業 08 年級 1 班
一、具體要求
本課程設計共2周,采取集中方式。㈠主要設計內容
1、進程調度
2、存儲管理
3、文件管理
㈡操作系統分項設計
1、設計一 :進程管理系統設計
目的與要求:本設計的目的是加深對進程概念及進程管理各部分內容的理解;熟悉進程管理中主要數據結構的設計及進程調度算法、進程控制機構、同步機構及通訊機構的實施。
要求設計一個允許n個進程并發運行的進程管理模擬系統。該系統包括有簡單的進程控制、同步與通訊機構,其進程調度算法可任意選擇。每個進程用一個PCB表示,其內容根據具體情況設置。各進程之間有一定的同步關系(可選)。系統在運行過程中應能顯示或打印各進程的狀態及有關參數的變化情況,以便觀察諸進程的運行過程及系統的管理過程。
具體詳見:設計任務書1--進程調度算法.doc
2、設計二:存貯器管理系統設計
目的與要求:本設計的目的是使學生熟悉存貯器管理系統的設計方法;加深對所學各種存貯器管理方案的了解;要求采用一些常用的存貯器分配算法,設計一個存貯器管理模擬系統并調試運行。模擬環境應盡量接近真實。
具體詳見:設計任務書2--內存分區管理模擬.doc
3、設計三:虛擬存儲器管理系統設計
本設計的目的是通過設計一個簡單的虛擬存儲器管理系統來模擬實際的頁面調度算法與過程,以掌握這種有用的技術。要求將其輸入/輸出處理程序編成一個獨立的進程模塊并與其它請求輸入/輸出的進程并發運行。并要求加入設備管理子模塊。
具體分析為:頁面調度算法主要有FIFO、最近最少使用調度算法(LRU)、最近最不常用調度算法(LFU)、最佳算法(OPT)等。題目要求:
① 實現三種算法:
1、先進先出;
2、OPT;
3、LRU ② 頁面序列從指定的文本文件(TXT文件)中取出
③ 輸出:第一行:每次淘汰的頁面號,第二行:顯示缺頁的總次數
4、設計四:文件管理系統設計
目的與要求:本設計的目的是通過設計和調試一個簡單的外部文件系統,主要是模擬文件操作,使學生對主要文件操作命令的實質和執行過程有比較深入的了解,掌握它們的基本實施方法。
基本要求如下:
實現三種算法: 先來先服務、最短尋道優先、電梯算法 磁道服務順序從指定的文本文件(TXT文件)中取出
輸出:第一行:磁道的服務順序;第二行:顯示移動總道數
5、設計五:多道程序的轉換調度系統 題目要求:(作業調度和進程調度結合在一起)作業流信息是從指定文本文件(TXT文件)中讀取 作業信息:
作業號 進入系統時間 估計運行時間 優先級 內存需求量 磁帶機需求量 都為整型 作業調度算法:先來先服務、最短作業優先(二者選一)
進程調度算法:先來先服務、基于優先級的算法(靜態優先級)(二者選一)輸出格式:作業號 時間間隔 800-810(/* 8:00-8:10 */)2 810-900 1 900-930平均周轉時間:總的周轉時間/作業總數
周轉時間就是作業結束時間減去作業進入系統時間 具體詳見:多道程序轉換.doc
以上設計以20-25人為組,選擇一個設計進行。㈢操作系統整體設計
將第㈡部分中的全部或部分有機地組合起來,構成一個小型的操作系統。
二、進度安排
1、教師下達設計任務書(半天)任務書內容包括題目、主要技術指標和要求、給定條件及原始數據、所用儀器設備和參考資料及文獻等。教師講授必要的設計思路和設計方法。
2、學生完成預設計(1天半)本階段學生通過查閱資料及文獻(主要自學),明確任務,掌握工程設計基本方法,確定設計方案,進行設計分析,完成預設計。
3、實驗階段(7天)經教師審查通過預設計方案后,即可進行編程調試。實驗由學生獨立完成,教師定時指導。
4、設計總結階段(1天)本階段學生要認真完成課程設計報告書,整理技術資料,并盡可能寫出課程設計的心得體會和改進意見。
三、完成后應上交的材料
課程設計報告書包括:設計任務及主要技術指標、設計方案及論證結果、系統的原理框圖、設計程序、實驗結果、實驗中主要問題及故障現象的分析及設計結論等。
附實驗數據、系統軟硬件環境、使用說明及參考資料。
四、總評成績
指導教師 簽名日期 年 月 日 系 主 任 審核日期 年 月 日
目 錄
一、實驗目的………………………………………5
二、實驗要求………………………………………5
三、具體內容………………………………………5 3.1先來先服務(FCFS)???????5 3.2作業優先SJF 算法????????5 3.3多級隊列調度算法????????.5 3.4時間片輪轉調度法?????????5 3.5優先級法?????????????6 3.6多隊列反饋法???????????6 3.7輪轉法??????????????.6 3.8最短周期優先???????????6 3.9先來先服務?????????????7
四、實驗程序………………………………………7
五、實驗總結………………………………………13
設計題目:進程管理系統設計
一、實驗目的:
本設計的目的是加深對進程概念及進程管理各部分內容的理解;熟悉進程管理中主要數據結構的設計及進程調度算法、進程控制機構、同步機構及通訊機構的實施。
二、實驗要求:
設計一個允許n個進程并發運行的進程管理模擬系統。該系統包括有簡單的進程控制、同步與通訊機構,其進程調度算法可任意選擇。每個進程用一個PCB表示,其內容根據具體情況設置。各進程之間有一定的同步關系(可選)。系統在運行過程中應能顯示或打印各進程的狀態及有關參數的變化情況,以便觀察諸進程的運行過程及系統的管理過程。
三、具體內容:
調度也稱dispatcher,這是內核的主要職責之一。一個良好的任務調度算法應該主要體現在以下幾個方面:
公平:保證每個進程得到合理的CPU 時間
高效:使CPU 保持忙碌狀態,即總是有進程在CPU 上運行 響應時間:使交互用戶的響應時間盡可能短
周轉時間:使批處理用戶等待輸出的時間盡可能短 吞吐量:使單位時間內處理的進程盡可能多
很顯然在任何操作系統中這幾個目標不可能同時達到所以不同的。
操作系統會在這幾個方面中做出相應的取舍從而確定自己的調度算法,常用的處理機調度算法有:先來先服務FCFS、短作業優先SJF、優先級、時間片輪轉法、多級隊列法、多級反饋隊列法。
(1)先來先服務(FCFS)
FCFS 是最簡單的CPU 調度算法,即按進程到來的先后次序進行調度,這樣在系統中等待時間最長的進程被優先調度,而不管其所需運行時間的長短。
(2)作業優先SJF 算法
是指當CPU 可供使用時SJF 算法把CPU 分給需要運行時間最短的進程。(3)多級隊列調度算法
把就緒隊列劃分成幾個單獨的隊列一般根據進程的某些特性如內存大小和進程類型永久性地把各個進程分別鏈入其中某一個隊列中,每個隊列都有自己的調度算法,此外在各個隊列之間也要進行調度。通常采用固定優先級的搶占式調度,例如某系統中有5 個隊列,各個隊列的優先級自上而下降低,只有當前3 個隊列中都為空的時候隊列4 中的進程才可以運行,而當隊列4 中的進程在運行時,如果隊列1 中進入了一個就緒進程,則隊列4 中的進程要立刻讓出CPU 使用權。多級反饋隊列法允許進程在各隊列間移動,其基本思想是把具有不同CPU工作時間這一特性的進程區分開來,如果一個進程要使用很長的CPU 時間,則應把它移至較低級的隊列中,這種方式把I/O 繁忙型和交互式進程放在較高優先級的隊列中同樣在低優先級隊列中長時間等待的進程可以移到較高優先級隊列中UNIX 系統采用的是多級反饋隊列輪轉法。
(4)時間片輪轉調度法
當兩個或兩個以上任務有同樣優先級,內核允許一個任務運行事先確定的一段時間叫做時間額度quantum,然后切換給另一個任務也叫做時間片調度time slicing,內核在滿足以下條件時把CPU 控制權交給下一個任務就緒態的任務,當前任務已無事可做,當前任務在時間片還沒結束時已經完成了。輪轉法主要是為分時系統設計的,其中時間片是一個重要的參數不能取的過大或過小,通常為10 至100ms 數量級,就緒隊列可以看成是一個環形隊列,CPU 調度程序輪流
地把CPU 分給就緒隊列中地每個進程,時間長度為一個時間片Linux 操作系統就是采用時間片輪轉的調度算法。
(5)優先級法
優先級調度的基本思想是,把當前處于就緒隊列中優先級最高的進程投入運行,而不管各進程的下一個CPU周期的長短和其他因素。
優先級通常用0~4095的整數(稱為優先數)表示,是數大優先級高還是數小優先級高取決于規定。例如UNIX系統規定優先數越大優先級越低,優先數越小優先級越高。
優先數有靜態和動態之分。靜態優先數是指在進程開始運行之前便根據某種或某些因素(如估計運行時間、主存需求量、打開文件個數、所付經費多少等)算定,而且該優先數在進程的整個生命周期內一直不變。靜態優先數方法雖然簡單,但有可能導致某些低優先級的進程無限期地等待。尤其在高優先級的進程不斷進入就緒隊列的情況下,使等待CPU的低優先級進程更多,等待時間更長。動態優先數方法是按照某種原則使各進程的優先級隨著時間而改變。例如隨等待時間增大優先級也跟著提高、隨著使用CPU時間的增長優先級跟著下降,就是一種較好的策略。等待了較長時間的進程,總會因其優先級不斷地提高而被調度運行。
如果把進入就緒隊列的次序作為計算進程動態優先數的主要指標,那么優先級法就變成FCFS。如果把下一個CPU周期最短作為計算進程動態優先數的主要指標,那么優先級法變成SBF,此時各進程的優先數p_pri = 1/ ti,其中ti是估算的下一個CPU周期的長度。
優先級調度也允許剝奪方式。現在的許多操作系統,例如UNIX系統V,Windows NT,OS/2等都采用優先級剝奪調度。
(6)多隊列反饋法
其基本思想是,把就緒進程按優先級排成多個隊列,同隊列的進程具有相同的時間片。高優先級隊列的時間片比低優先級隊列的小。調度時先從高優先級隊列中選出某一進程投入運行,當該進程的時間片到期后則轉至低一級的就緒隊列中。只有高優先級隊列為空時才從低一級隊列中調度進程。
例如考慮由3個隊列組成的多級隊列調度。3個隊列的編號分別為0, 1, 2,如圖所示。調度算法首先調度0號隊列中的進程。當0號隊列為空時才調度1號隊列中的進程;當0號與1號隊列都為空時才調度2號隊列中的進程。在剝奪方式下,新進入0號隊列的進程將剝奪1號或2號隊列中正在執行的進程的CPU,而新進入1號隊列的進程將剝奪2號隊列中正在執行的進程的CPU。
其實,每個隊列都可擁有各自的調度算法,也可制定不同的“轉隊”規則。這樣看來,多隊列反饋調度算法能有多種變化。
(7)輪轉法
輪轉法就是按一定時間片(記為q)輪番運行各個進程。如果q是一個定值,則輪轉法是一種對各進程機會均等的調度方法。
輪轉法本質上是剝奪的,因為一輪內,每個進程不能獲得比一個時間片q更長的運行時間。正是由于這一特點,輪轉法特別適用于分時操作系統。
輪轉法的關鍵問題是如何確定q的大小。如果時間片太大以致每個進程的CPU周期都能在一個時間片內完成,則輪轉法實際上脫化為FCFS。如果q太小以致CPU切換過于頻繁,則會增加CPU的額外開銷,降低了CPU的有效利用率。這是因為,每次CPU切換涉及到保存原運行進程的現場和恢復新運行進程的現場,這些操作一般需要10ms~100ms的時間。例如,設有一個CPU周期為10單位的進程,在q取12,6,1時的調度次數分別為0,1,9。令時間單位為1ms(1ms=1000ms),1次調度的開銷為100ms,則在q=1時CPU的額外開銷和有效開銷之比為1:10,這是不容忽視的。
(8)最短周期優先
最短周期優先(SBF: shortest burst first)把當前就緒隊列中的下一個CPU周期最短的那個進程調度運行。
(9)先來先服務
如果早就緒的進程排在就緒隊列的前面,遲就緒的進程排在就緒隊列的后面,那么先來先服務(FCFS: first come first service)總是把當前處于就緒隊列之首的那個進程調度到運行狀態。也就說,它只考慮進程進入就緒隊列的先后,而不考慮它的下一個CPU周期的長短及其他因素。FCFS算法簡單易行,但性能卻不大好。
四、實驗程序
#include “iostream.h”
//define pcb typedef struct pcb { char name[10];//進程名
char state;//狀態w(就緒)r(運行)f(結束)int id;//id號
int super;//優先級
int ntime;//需運行的時間 int rtime;//已運行的時間 struct pcb *next;}*pcb1;
pcb1 s,w;//define two publiced linknode ,one is s(ready queue),one is w(blocked queue)
//initialize two queues void init(pcb1 &r){ r=NULL;//both queues is the kind of head index }
//print the information of the ready queue void print(){pcb1 p;cout<<“您現在查看的是就緒隊列的信息:”;cout<<“進程號 ”<<“進程名 ”<<“優先級 ”<<“狀態”<<“已運行時間 ”<<“需運行時間”<
cout<
id<<“ ”<
name<<“ ”<
super<<“ ”<
state<<“ ”<
rtime<<“ ”<
ntime< //print the information of the blocked queue void print1(){pcb1 p;cout<<“您現在查看的是阻塞隊列的信息”;cout<<“進程號 ”<<“進程名 ”<<“優先級 ”<<“狀態 ”<<“已運行時間 ”<<“需運行時間”< id<<“ ”< name<<“ ”< super<<“ ”< state<<“ ”< rtime<<“ ”< ntime< //check the queue if empty int empty(pcb1 &r){ if(r==NULL)return 0;else return 1;} //check the first process of the ready queue if finshed int check(){ pcb1 p;p=s;if(p->rtime==p->ntime){ p->state='F';//if one process finshed then change ti's state cout<<“進程”< id<<“ 已經結束”< //sort process according to the super of the process and insert to the ready(blocked)queue void sort(pcb1 &r,pcb1 p){ pcb1 p1,p2;int in=0;if(r==NULL)//the queue is empty { r=p;} else { if(p->super>=r->super)//the super of the process which wait insert to the queue is highter than the super of the first process of the queue { p->next=r;r=p;} else { p1=r;p2=r->next;if(p2==NULL)//only one process in the queue { r->next=p;} else { while(in==0&&p2!=NULL)//insert to the middle of the queue { if(p->super>=p2->super){ p->next=p2;p1->next=p;in=1;} else { p1=p1->next;p2=p2->next;} } } if(in==0)//link to the last of ready queue p1->next=p;} } } //block one process and insert to block queue void block(){ if(empty(s)){ if(s->next==NULL){ sort(w,s);s=s->next;} else { pcb1 p1;p1=s;s=s->next;p1->next=NULL;sort(w,p1);} } else { cout<<“現在就緒隊列已經為空,再沒有進程需要阻塞”< //wake one process of block queue and insert to ready queue void wake(){ if(empty(w)){ pcb1 p1;p1=w;w=w->next;p1->next=NULL;sort(s,p1);} else { cout<<“阻塞隊列已經為空,沒有進程再需要喚醒”< //runing void runing(){ if(empty(s)){ pcb1 p;p=s;if(check())//check the first process of the queue if finished {//no s=s->next;p->rtime++;p->super--;p->next=NULL;sort(s,p);} else {//yes s=s->next;} } else { cout<<“就緒隊列已經為空”< //creat process void input(){ pcb1 p2;p2=new pcb;cout<<“請輸入 進程號、進程名、進程優先級、需要運行時間”;cin>>p2->id>>p2->name>>p2->super>>p2->ntime;p2->rtime=0;p2->state='W';p2->rtime=0;p2->next=NULL; sort(s,p2);} //main function void main(){ char ch;init(s);init(w);cout<<“*****************************進程調度模擬程序開始*******************************”< 程序運行界面如下: 五、實驗總結 本次實驗,我的任務是設計一個允許n個進程并發運行的進程管理模擬系統。該系統包括有簡單的進程控制、同步與通訊機構,系統在運行過程中能顯示各進程的狀態及有關參數的變化情況,從而觀察諸進程的運行過程及系統的管理過程,我是用C++寫的,在我的電腦能夠運行通過,雖不能盡善盡美,但也基本能實現老師的要求。 兩個星期程序設計課程,雖然時間有點短,但我也收獲不少,這次試驗,加深了我對進程概念及進程管理的理解;比較熟悉進程管理中主要數據結構的設計及進程調度算法、進程控制機構、同步機構及通訊機構的實施。也讓我認識到自己的不足,操作系統的有些知識,我知道的還不多,沒有掌握好,還需要多多學學,不斷提升自己的能力。 進程調度算法模擬 專業:XXXXX 學號:XXXXX 姓名:XXX 實驗日期:20XX年XX月XX日 一、實驗目的 通過對進程調度算法的模擬加深對進程概念和進程調度算法的理解。 二、實驗要求 編寫程序實現對5個進程的調度模擬,要求至少采用兩種不同的調度算法分別進行模擬調度。 三、實驗方法內容 1.算法設計思路 將每個進程抽象成一個控制塊PCB,PCB用一個結構體描述。 構建一個進程調度類。將進程調度的各種算法分裝在一個類中。類中存在三個容器,一個保存正在或未進入就緒隊列的進程,一個保存就緒的進程,另一個保存已完成的進程。還有一個PCB實例。主要保存正在運行的進程。類中其他方法都是圍繞這三個容器可以這個運行中的PCB展開。 主要用到的技術是STL中的vector以維護和保存進程容器、就緒容器、完成容器。 當程序啟動時,用戶可以選擇不同的調度算法。然后用戶從控制臺輸入各個進程的信息,這些信息保存到進程容器中。進程信息輸入完畢后,就開始了進程調度,每調度一次判斷就緒隊列是否為空,若為空則系統時間加一個時間片。判斷進程容器中是否有新的進程可以加入就緒隊列。2.算法流程圖 主程序的框架: 開始void FCFS();//先來先服務void SJF();//最短進程優先調度void RR();//簡單時間片輪轉void PD();//最高優先數優先void PCBInput();//輸入進程信息選擇調度算法輸入進程信息將輸入容器中以滿足進入條件的進程調入就緒隊列void ProcessQueueProcess();//查看當前時間下,有無進程加入。若有則把該進程調入就緒隊列按照選擇的算法開始選擇就緒隊列的進程開始執行void ProcessSelect();//若當前就緒隊列不為空則根據選擇的調度算法開始調度,否則,系統時間加一個時間片.以等待新的進程到判斷就緒容器和輸入容器是否為空!processScheduler.m_WaitQueue.empty()||!processScheduler.m_ProcessQueue.empt()Y打印各進程信息進行統計計算周轉時間等結束void PCBDisplay();//打印當前狀況下。就緒隊列、完成隊列、運行中的進程信息void SchedulerStatistics();//調度統計,計算周轉時間等進程調度過程: 開始為空判斷就緒隊列是否為空if(m_WaitQueue.empty())非空讓系統等待一個時間片TimePast()根據設定的調度算法從就緒隊列中調入一個進程并執行(此時進程從就緒隊列中刪除,賦值到表示運行中的成員變量中)void FCFS();//先來先服務void SJF();//最短進程優先調度void RR();//簡單時間片輪轉void PD();//最高優先數優先進程運行一個時間片N是否達到該進程停止運行的條件Y選入的進程狀態是否為“完成”如進程已完成,或者分得的時間片個數已到ProcessRun()Yvector m_WaitQueue;//進程就緒隊列進程未完成,將進程優先數減一,并放回到就緒隊列中設置進程完成時間,將該進程放入完成隊列vector m_FinishQueue;//完成隊列結束 3.算法中用到的數據結構 struct fcfs{ //先來先服務算法從這里開始 char name[10]; float arrivetime; float servicetime; float starttime; float finishtime; float zztime; float dqzztime; }; //定義一個結構體,里面包含的有一個進程相關的信息 4.主要的常量變量 vector m_ProcessQueue;//進程輸入隊列 vector m_WaitQueue;//進程就緒隊列 vector m_FinishQueue;//完成隊列 vector ::iterator m_iter;//迭代器 PCB m_runProcess;//運行中的進程 int m_ProcessCount;//進程數 float m_RunTime;//運行時間 int m_tagIsRun;//是否在運行標志。表示正在運行,表示沒有 float m_TimeSlice;//時間片大小 int m_TimeSliceCount;//指時間片輪轉中一次分到的時間片個數 char m_SchedulerAlgorithm;//調度算法 5.主要模塊 void PCBInput();//輸入進程信息 void PCBSort();//對進程控制塊按照優先級排序(采用冒泡排序)void ProcessSelect();//若當前就緒隊列不為空則根據選擇的調度算法開始調度。否則,系統時間void PCBDisplay();//打印當前狀況下。就緒隊列、完成隊列、運行中的進程信息 void ProcessRun();//進程運行一次。運行時間加個時間片。并判斷進程是否達到完成條件。若是則void ProcessQueueProcess();//查看當前時間下,有無進程加入。若有則把該進程調入就緒隊列 void ProcessDispatch();//進程分派,進程執行完成后決定進程該進入哪個隊列(就緒、完成)void TimePast(){ m_RunTime +=m_TimeSlice;ProcessQueueProcess();}//當前系統時間加個時間void SchedulerStatistics();//調度統計,計算周轉時間等 void FCFS();//先來先服務 void SJF();//最短進程優先調度 void RR();//簡單時間片輪轉 void PD();//最高優先數優先 加.以等待新的進程到來 ProcessStatus='f'.否則為'w';片,并檢查是否有新的進程加入 四、實驗代碼 #include using namespace std; struct fcfs{ //先來先服務算法從這里開始 char name[10]; float arrivetime; float servicetime; float starttime; float finishtime; float zztime; float dqzztime; }; //定義一個結構體,里面包含的有一個進程相關的信息 fcfs a[100]; void input(fcfs *p,int N) { int i; cout< printf(“ 請您輸入進程的名字 到達時間 服務時間:(例如: a 0 100)nn”); for(i=0;i<=N-1;i++) { printf(“ 請您輸入進程%d的信息:t”,i+1); scanf(“ttt%s%f%f”,&p[i].name,&p[i].arrivetime,&p[i].servicetime); } } void Print(fcfs *p,float arrivetime,float servicetime,float starttime,float finishtime,float zztime,float dqzztime,int N) { int k; printf(“nn調用先來先服務算法以后進程運行的順序是: ”); printf(“%s”,p[0].name); for(k=1;k { printf(“-->%s”,p[k].name); } cout< printf(“n 具體進程調度信息:n”); printf(“t進程名 到達時間 服務時間 開始時間 結束時間 周轉時間 帶權周轉時間n”); for(k=0;k<=N-1;k++) { printf(“t%st%-.2ft %-.2ft %-.2ft %-.2ft %-.2ft %-.2fn”,p[k].name,p[k].arrivetime,p[k].servicetime,p[k].starttime,p[k].finishtime,p[k].zztime,p[k].dqzztime); } getchar(); //此處必須要有這個函數,否則就看不到顯示器上面的輸出,可以看到的結果只是一閃而過的一個框剪 } void sort(fcfs *p,int N)//排序 { for(int i=0;i<=N-1;i++) for(int j=0;j<=i;j++) if(p[i].arrivetime { fcfs temp; temp=p[i]; p[i]=p[j]; p[j]=temp; } } void deal(fcfs *p, float arrivetime,float servicetime,float starttime,float finishtime,float &zztime,float &dqzztime,int N) //運行階段 { int k; for(k=0;k<=N-1;k++) { if(k==0) { p[k].starttime=p[k].arrivetime; p[k].finishtime=p[k].arrivetime+p[k].servicetime;} else { p[k].starttime=p[k-1].finishtime; p[k].finishtime=p[k-1].finishtime+p[k].servicetime;} } for(k=0;k<=N-1;k++) { p[k].zztime=p[k].finishtime-p[k].arrivetime; p[k].dqzztime=p[k].zztime/p[k].servicetime; } } void FCFS(fcfs *p,int N) { float arrivetime=0,servicetime=0,starttime=0,finishtime=0,zztime=0,dqzztime=0; sort(p,N); deal(p,arrivetime,servicetime,starttime,finishtime,zztime,dqzztime,N); Print(p,arrivetime,servicetime,starttime,finishtime,zztime,dqzztime,N); getchar(); } //先來先服務算法到此結束 struct sjf{//最短進程優先調度算法從這里開始 char name[10];float arrivetime;//到達時間 float servicetime;//運行時間 float starttime; //開始時間 float finishtime; //完成時間 };sjf a1[100]; void input(sjf *p,int N1)//進程信息輸入 { int i;cout< printf(“ 請您輸入進程的名字 到達時間 服務時間:(例如: a 0 100)n”); for(i=0;i<=N1-1;i++){ printf(“ 請您輸入進程%d的信息:t”,i+1); scanf(“ttt%s%f%f”,&p[i].name,&p[i].arrivetime,&p[i].servicetime);} } void Print(sjf *p,float arrivetime,float servicetime,float starttime,float finishtime,int N1)//最終結果輸出 { int k; printf(“nt調用最短進程優先調度算法以后進程的調度順序為:”); printf(“%s”,p[0].name); for(k=1;k {printf(“-->%s”,p[k].name);} cout< printf(“n給個進程具體調度信息如下:n”); printf(“nt進程名t到達時間t運行時間t開始時間t完成時間n”); for(k=0;k<=N1-1;k++) { printf(“ t%st %-.2ftt %-.2ftt %-.2ftt %-.2ftn”,p[k].name,p[k].arrivetime,p[k].servicetime,p[k].starttime,p[k].finishtime); } getchar(); } void sort(sjf *p,int N1)//排序 { for(int i=0;i<=N1-1;i++) for(int j=0;j<=i;j++) if(p[i].arrivetime { sjf temp; temp=p[i]; p[i]=p[j]; p[j]=temp; } } void deal(sjf *p, float arrivetime,float servicetime,float starttime,float finishtime,int N1)//運行階段 { int k; for(k=0;k<=N1-1;k++) { if(k==0) { p[k].starttime=p[k].arrivetime; p[k].finishtime=p[k].arrivetime+float(p[k].servicetime)/60;} else { p[k].starttime=p[k-1].finishtime; p[k].finishtime=p[k-1].finishtime+float(p[k].servicetime)/60;} } } void sjff(sjf *p,int N1){ float arrivetime=0,servicetime=0,starttime=0,finishtime=0; sort(p,N1); for(int m=0;m {if(m==0) p[m].finishtime=p[m].arrivetime+float(p[m].servicetime)/60; else p[m].finishtime=p[m-1].finishtime+float(p[m].servicetime)/60; int i=0; for(int n=m+1;n<=N1-1;n++) { if(p[n].arrivetime<=p[m].finishtime) i++; } float min=p[m+1].servicetime; int next=m+1; for(int k=m+1;k { if(p[k+1].servicetime {min=p[k+1].servicetime; next=k+1;} } sjf temp; temp=p[m+1]; p[m+1]=p[next]; p[next]=temp; } deal(p,arrivetime,servicetime,starttime,finishtime,N1); Print(p,arrivetime,servicetime,starttime,finishtime,N1); getchar();}//最短進程優先調度算法到這里結束 char menu()//用來輸出相關信息的函數 { char cse1; while(1) { system(“cls”); fflush(stdin); cout< cout< cout<<“t”<<“|| <<<<<<<<<<<<歡<<<<<<<<<<< >>>>>>>>>>>>迎>>>>>>>>>>> ||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“t 進程調度算法模擬”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“tt 1.先來先服務調度算法 ”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“||”<<“tt 2.最短進程優先調度算法”<<“tt”<<“||”< cout<<“t”<<“|| ||”< cout<<“t”<<“|| <<<<<<<<<<<<<<<<<<<<<<<<<您>>>>>>>>>>>>>>>>>>>>>>>>> ||”< cout< cout< cout<<“tt 請輸入您的選擇(1/2):”; cse1=getchar(); if(cse1<'1'||cse1>'2') cout<<“你的輸入有錯!”< else break; } return cse1;} int main(int argc, char *argv[]){ while(1) { switch(menu()) { case '1': int N; cout< cout< printf(“tt<<---!!@@@先來先服務調度算法@@@!!--->>n”); cout< printf(“輸入進程數目:”); scanf(“%d”,&N); input(a,N); FCFS(a,N); case '2': int N1; cout< cout< printf(“tt<<---!!@@@最短進程優先調度算法@@@!!--->>n”); cout< printf(“輸入進程數目: ”); scanf(“%d”,&N1); input(a1,N1); sjf *b=a1; sjf *c=a1; sjff(b,N1); getchar(); } } system(“PAUSE”); return EXIT_SUCCESS;} 五、實驗結果 1.執行結果 2.結果分析 先來先服務調度算法就是根據進程達到的時間為依據,哪一個進程先來那么該進程就會先執行;最短進程優先調度算法則是以每個進程執行所需時間長短為依據,某一個進程執行所需花的時間要短些那么該進程就先執行。以上就是本次進程調度實驗的依據。 六、實驗總結 通過本次實驗了解到算法很重要,又更加明白算法本身可以節約時間,而且不同的函數之間在調用的時候要注意很多的問題。 實驗二 進程調度 1.目的和要求 通過這次實驗,理解進程調度的過程,進一步掌握進程狀態的轉變、進程調度的策略,進一步體會多道程序并發執行的特點,并分析具體的調度算法的特點,掌握對系統性能的評價方法。 2.實驗內容 閱讀教材《計算機操作系統》第二章和第三章,掌握進程管理及調度相關概念和原理。 編寫程序模擬實現進程的輪轉法調度過程,模擬程序只對PCB進行相應的調度模擬操作,不需要實際程序。假設初始狀態為:有n個進程處于就緒狀態,有m個進程處于阻塞狀態。采用輪轉法進程調度算法進行調度(調度過程中,假設處于執行狀態的進程不會阻塞),且每過t個時間片系統釋放資源,喚醒處于阻塞隊列隊首的進程。 程序要求如下: 1)輸出系統中進程的調度次序; 2)計算CPU利用率。 3.實驗環境 Windows操作系統、VC++6.0 C語言 4設計思想: (1) 程序中進程可用PCB表示,其類型描述如下: struct PCB_type { int pid; //進程名 int state; //進程狀態 2——表示“執行”狀態 1——表示“就緒”狀態 0——表示“阻塞”狀態 int cpu_time;//運行需要的CPU時間(需運行的時間片個數) } 用PCB來模擬進程; (2)設置兩個隊列,將處于“就緒”狀態的進程PCB掛在隊列ready中;將處于“阻塞”狀態的進程PCB掛在隊列blocked中。隊列類型描述如下: struct QueueNode{ struct PCB_type PCB; Struct QueueNode *next;} 并設全程量: struct QueueNode *ready_head=NULL,//ready隊列隊首指針 *ready_tail=NULL , //ready隊列隊尾指針 *blocked_head=NULL,//blocked隊列隊首指針 *blocked_tail=NULL;//blocked隊列隊尾指針(3)設計子程序: start_state(); 讀入假設的數據,設置系統初始狀態,即初始化就緒隊列和阻塞隊列。 dispath(); 模擬調度,當就緒隊列的隊首進程運行一個時間片后,放到就緒隊列末尾,每次都是隊首進程進行調度,一個進程運行結束就從就緒隊列中刪除,當到t個時間片后,喚醒阻塞隊列隊首進程。 calculate(); 就緒進程運行一次,usecpu加1,當就緒隊列為空時unusecpu加1,CPU利用率為use_cpu/(use_cpu+unuse_cpu)。 5源代碼: #include struct PCB_type { int pid; //進程名 int state; //進程狀態 //2--表示“執行”狀態 //1--表示“就緒”狀態 //0--表示“阻塞”狀態 int cpu_time;//運行需要的CPU時間(需運行的時間片個數)};struct QueueNode{ struct PCB_type PCB; struct QueueNode *next;};struct QueueNode *ready_head=NULL,//ready隊列隊首指針 *ready_tail=NULL,//ready隊列隊尾指針 *block_head=NULL,//blocked隊列隊首指針 *block_tail=NULL; //blocked隊列隊尾指針 int use_cpu,unuse_cpu; void start_state()//讀入假設的數據,設置系統初始狀態 { int n,m; int i; struct QueueNode *p,*q; printf(“輸入就緒節點個數n:”); scanf(“%d”,&n); printf(“輸入阻塞節點個數m:”); scanf(“%d”,&m); p=(struct QueueNode *)malloc(sizeof(struct QueueNode)); p->next =NULL; ready_head=ready_tail=p; for(i=0;i { p=(struct QueueNode *)malloc(sizeof(struct QueueNode)); p->next =NULL; p->PCB.state=1; printf(“輸入就緒進程%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&p->PCB.pid,&p->PCB.cpu_time); ready_tail->next=p; ready_tail=p; } q=(struct QueueNode *)malloc(sizeof(struct QueueNode)); q->next =NULL; block_head=block_tail=q; for(i=0;i { q=(struct QueueNode *)malloc(sizeof(struct QueueNode)); q->next=NULL; q->PCB.state=0; printf(“輸入阻塞進程%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&q->PCB.pid,&q->PCB.cpu_time); block_tail->next=q; block_tail=q; } printf(“n處于就緒狀態的進程有:n”); p=ready_head->next; i=1; while(p) {printf(“進程%d的pid和cpu_time:%5d%5d%5dn“,i,p->PCB.pid,p->PCB.state,p->PCB.cpu_time); p=p->next; i++; } } void dispath() //模擬調度 { int x=0,t; use_cpu=0; unuse_cpu=0; printf(”輸入t:“); scanf(”%d“,&t); printf(”開始調度n“); while(ready_head!=ready_tail||block_head!=block_tail) { struct QueueNode *p,*q; if(ready_head!=ready_tail) { p=ready_head->next; ready_head->next=p->next; p->next=NULL; if(ready_head->next==NULL) { ready_tail=ready_head; } p->PCB.state=2; printf(”進程%d調度t“,p->PCB.pid); state和 use_cpu++; x++; p->PCB.cpu_time--; if(p->PCB.cpu_time) { ready_tail->next=p; ready_tail=p; } else { printf(”進程%d完成t“,p->PCB.pid); free(p); } } else { unuse_cpu++; x++; printf(”空閑一個時間片t“); } if(x==t&&block_head!=block_tail) { q=block_head->next; block_head->next=q->next; q->next=NULL; if(block_head->next==NULL) { block_tail=block_head; } ready_tail->next=q; ready_tail=q; x=0; } } } void calculate() //計算CPU利用率 { printf(”ncpu的利用率%.2fn“,(float)use_cpu/(use_cpu+unuse_cpu)); } void main(){start_state(); dispath(); calculate();} 6運行結果: 7實驗總結: 實驗幫我復習了數據結構和C語言,且鞏固課本知識,知道了如何定義結構體,如何在鏈接隊列中增刪節點。模擬進程調度幫我們鞏固了進程三狀態之間的變遷。懂得調式的重要性。總之,我們明白了理論聯系實際。多看書,多上機。 實驗三 可變分區存儲管理 1.目的和要求 通過這次實驗,加深對內存管理的認識,進一步掌握內存的分配、回收算法的思想。 2.實驗內容 閱讀教材《計算機操作系統》第四章,掌握存儲器管理相關概念和原理。編寫程序模擬實現內存的動態分區法存儲管理。內存空閑區使用自由鏈管理,采用最壞適應算法從自由鏈中尋找空閑區進行分配,內存回收時假定不做與相鄰空閑區的合并。 假定系統的內存共640K,初始狀態為操作系統本身占用64K。在t1時間之后,有作業A、B、C、D分別請求8K、16K、64K、124K的內存空間;在t2時間之后,作業C完成;在t3時間之后,作業E請求50K的內存空間;在t4時間之后,作業D完成。要求編程序分別輸出t1、t2、t3、t4時刻內存的空閑區的狀態。 3.實驗環境 Windows操作系統、VC++6.0 C語言 4.設計思想 模擬內存分配和回收,要設置兩個鏈隊列,一個空閑區鏈和一個占用區鏈,空閑區鏈節點有起始地址,大小和指向下一節點的指針等數據域,占用區鏈節點有起始地址,大小,作業名和指向下一節點的指針等數據域,本實驗用最壞適應算法,每次作業申請內存都是從空閑鏈隊頭節點分配,如果相等,就刪除空閑頭結點,如果小于申請的,就不分配,否則就劃分內存給作業,剩下的內存大小,重新插入空閑鏈隊,按從大到小,接著把作業占用的內存放到占用區鏈節點的末尾。每次作業運行完,就要回收其占用的內存大小,把作業節點按從大到小插入到空閑鏈隊中。5.源代碼: #include struct freelinkNode *next;};struct busylinkNode{ char name; int len;int address;struct busylinkNode *next;};struct freelinkNode *free_head=NULL; //自由鏈隊列(帶頭結點)隊首指針 struct busylinkNode *busy_head=NULL; //占用區隊列隊(帶頭結點)首指針 struct busylinkNode *busy_tail=NULL; //占用區隊列隊尾指針 void start(void)/* 設置系統初始狀態*/ { struct freelinkNode *p; struct busylinkNode *q; free_head=(struct freelinkNode*)malloc(sizeof(struct freelinkNode)); free_head->next=NULL;// 創建自由鏈頭結點 busy_head=busy_tail=(struct busylinkNode*)malloc(sizeof(struct busylinkNode)); busy_head->next=NULL;// 創建占用鏈頭結點 p=(struct freelinkNode *)malloc(sizeof(struct freelinkNode)); p->address=64; p->len=640-64;//OS占用了64K p->next=NULL; free_head->next=p; q=(struct busylinkNode *)malloc(sizeof(struct busylinkNode)); q->name='S';/* S表示操作系統占用 */ q->len=64;q->address=0;q->next=NULL; busy_head->next=q;busy_tail=q;} void requireMemo(char name, int require)/*模擬內存分配*/ { freelinkNode *w,*u,*v;busylinkNode *p;if(free_head->next->len>=require){ p=(struct busylinkNode*)malloc(sizeof(struct busylinkNode)); p->name=name; p->address=free_head->next->address; p->len=require; p->next=NULL; busy_tail->next=p; busy_tail=p;} else printf(”Can't allocate“); w=free_head->next; free_head->next=w->next; if(w->len==require) { free(w);} else { w->address=w->address+require; w->len=w->len-require;} u=free_head; v=free_head->next; while((v!=NULL)&&(v->len>w->len)){ u=v; v=v->next;} u->next=w; w->next=v;} void freeMemo(char name)/* 模擬內存回收*/ { int len; int address;busylinkNode *q,*p;freelinkNode *w,*u,*v;q=busy_head; p=busy_head->next; while((p!=NULL)&&(p->name!=name)) { q=p; p=p->next;} if(p==NULL){ printf(”%c is not exist“,name);} else { if(p==busy_tail) { busy_tail=q; } else { q->next=p->next; len=p->len; address=p->address; free(p); w=(struct freelinkNode*)malloc(sizeof(struct freelinkNode)); w->len=len; w->address=address; u=free_head; v=free_head->next; while((v!=NULL)&&(v->len>len)) { u=v;v=v->next; } u->next=w; w->next=v; } } } void past(int time)/* 模擬系統過了time 時間*/ { printf(”過了時間%d后:n“,time);} void printlink()/* 輸出內存空閑情況(自由鏈的結點)*/ { freelinkNode *p; printf(”內存的空閑情況為:n“); p=(struct freelinkNode *)malloc(sizeof(struct freelinkNode)); p=free_head->next; while(p!=NULL) { printf(”內存的起始地址和內存的大小%5dt%5d:n",p->address,p->len); p=p->next; } } void main(){ int t1=1,t2=2,t3=3,t4=4; start(); past(t1); requireMemo('A',8); requireMemo('B',16); requireMemo('C',64); requireMemo('D',124); printlink(); past(t2); freeMemo('C'); printlink(); past(t3); requireMemo('E',50); printlink(); past(t4); freeMemo('D'); printlink();} 6.運行結果: 7.實驗總結: 鞏固編程能力,和調式能力,復習課本知識,明白理論聯系實際的重要性,動手能力非常重要,多看書,多獨立思考,品味痛苦的過程,享受成功的喜悅。 操作系統實驗報告 院系:數計學院 班級:大類6班 學號:100511624 姓名:明章輝 指導教師:徐軍利 許昌學院 《操作系統》實驗報告書 學號:姓名:閆金科班級:成績: 5006140057 14物聯網工程 2016年02月實驗一 Linux的安裝與配置 一、實驗目的 1.熟悉Linux系統的基本概念,比如Linux發行版、宏內核、微內核等。2.掌握Linux系統的安裝和配置過程,初步掌握Linux系統的啟動和退出方法。3.熟悉Linux系統的文件系統結構,了解Linux常用文件夾的作用。 二、實驗內容 1.從網絡上下載VMware軟件和兩個不同Linux發行版鏡像文件。2.安裝VMware虛擬機軟件。 3.在VMware中利用第一個鏡像文件完成第一個Linux的安裝,期間完成網絡信息、用戶信息、文件系統和硬盤分區等配置。 4.在VMware中利用第二個鏡像文件完成第二個Linux的安裝,并通過LILO或者GRUB解決兩個操作系統選擇啟動的問題。 5.啟動Linux系統,打開文件瀏覽器查看Linux系統的文件結構,并列舉出Linux常用目錄的作用。 三、實驗過程及結果 1、啟動VMware,點擊新建Linux虛擬機,如圖所示: 2、點擊下一步,選擇經典型,點擊下一步在選擇客戶機頁面選擇Linux,版本選擇Red Hat Enterprise Linux 5,如圖所示: 3、點擊下一步創建虛擬機名稱以及所要安裝的位置,如圖所示: 4、點擊下一步,磁盤容量填一個合適大小,此處選擇默認值大小10GB,如圖所示: 5、點擊完成,點擊編輯虛擬機設置,選擇硬件選項中的CD-ROM(IDE...)選項,在右側連接中選擇“使用ISO鏡像(I)”選項,點擊“瀏覽”,找到Linux的鏡像文件,如圖所示: 6點擊確定按鈕后,點擊啟動虛擬機按鈕,來到Linux的安裝界面,如圖所示: 7、到此頁面之后,等待自動檢測安裝,如圖所示: 8、等到出現如圖所示頁面后點擊“skip”按鈕,跳過檢測,直接進入安裝設置界面,如圖所示: 9、安裝設計界面如圖所示: 10、點擊Next按鈕進入設置語言界面,設置語言為“簡體中文”,如圖所示: 11、點擊Nest按鈕進入系統鍵盤設置按鈕,設置系統鍵盤為“美國英語式”,如圖所示: 12、點擊下一步按鈕,彈出“安裝號碼”對話框,選擇跳過輸入安裝號碼,如圖所示: 13、按照提示,一直點擊下一步按鈕,如圖所示: 14、到設置最后一步,點擊下一步按鈕進入開始安裝Red Hat Enterprise Linux Sever界面,如圖所示: 15、安裝完成后,進入歡迎界面,按照提示點擊前進按鈕知道進入Linux桌面,如圖所示: 16、安裝成功的Linux系統桌面如圖所示,桌面包含五個圖標,分別為:計算機、jk’s Home、回收站、RHEL/5.3 i386DVD。 四、實驗總結 通過安裝虛擬機等操作讓我認識到Linux這系統一些基本特點,本次試驗學會了安裝虛擬機并且使用虛擬機安裝操作系統,掌握了紅帽Linux系統的安裝和配置過程,以及對鏡像ISO文件的使用,有別于我們機器上使用的系統,通過虛擬機這個軟件還可以在已有系統的基礎上使用其他操作系統。安裝過程中一定要注意選擇版本的時候要選擇Red Hat Enterprise Linux 5版本,否則安裝不能成功。自己動手成功的安裝了Linux系統,自己對Linux的學習產生更大的興趣。 實驗二 Linux操作系統的運行模式 一、實驗目的 1.熟悉Linux系統終端工作環境的使用,了解Linux命令的格式,使用學會利用常用的Linux命令來完成系統的管理和維護。 2.了解X-Windows的特點,熟悉Linux圖形用戶接口的使用,掌握GNOME桌面環境的基本操作。 3.了解和掌握在Linux環境下安裝軟件包的方法,如QQ for Linux等用軟件的安裝方法。 二、實驗內容 1.啟動Linux系統打開虛擬終端界面,使用Linux的在線幫助指令man或help獲得ls、uname、date、cal、mkdir、cp等Linux命令的幫助手冊,了解這些命令的具體使用方法。同時,也可以通過執行“命令名 –help”來顯示該命令的幫助信息,如“ls –help”,試用這些命令。 2.通過uname命令的執行,查看并給出相關系統信息:操作系統的名稱、系統域名、系統CPU名稱等。 3.在主目錄下創建一個名為myetc的子目錄,將/etc目錄下與網絡相關的文件和子目錄拷貝到該目錄,并將這些文件的執行權限設置為可執行。 4.在主目錄/home下創建目錄program、music 和temp,然后在program下建立目錄java和C,列出完成該過程的所有命令。 5.在圖形界面環境中,查看GNOME桌面的面板和桌面,設置GNOME,包括屏幕保護程序、更改背景和指定關聯程序等。6.實現對光盤的加載和訪問,然后卸載。 三、實驗過程及結果 1、打開終端,輸入 【ls –help】來查看【ls】指令的使用方法,同理查看uname、date、cal、mkdir、cp的使用方法。 2、在終端中輸入【uname –a】顯示操作系統名系統cpu名和系統域名 3、重啟系統,用【root】用戶名進入系統,以獲得權限。在終端中輸入【mkdir myetc】,在主目錄下創建【myrtc】的目錄,【ls】查看是否創建。輸入【cd..】返回至【/】文件,輸入【cp –r etc root/myetc】講etc中內容復制到myetc中,進入myetc文件【ls】查看。輸入 【chmod u+x etc】賦予文件可執行的權限,輸入【ll】查看。 4、在home下,輸入【mkdir {program,music,temp}】,可在home下創立這三個目錄,輸入【ls】查看。在program下輸入【mkdir{java,C}】,可創立java和C兩個目錄,【ls】查看。 5、在桌面上方選擇【系統】-【首選項】,即可設置屏幕保護程序和更改背景和指定關聯程序 5、在桌面上可見看到有CD光盤,雙擊瀏覽,右鍵【彈出】即卸載。 四、實驗總結和體會 Linux的指令系統是學習Linux操作系統很重要的一部分,指令系統相當于在Windows操作系統下的doc,可以省去圖形化界面。通過這次的實驗讓我了解了Linux的強大功能,了解到Linux有許多方便快捷的設置基本配置的方法,這使我更喜歡上Linux的使用。在使用指令的過程中,有時候對文件的操作需要一定的權限,這時需要在登陸時用戶名使用【root】,而不是我們在安裝時使用的用戶名,這樣就獲得了管理員權限,可以對一些系統文件進行操作。 實驗三 Linux應用軟件與系統管理 一、實驗目的 1.了解OpenOffice.Org集成辦公軟件,掌握利用OpenOffice.Org的套件來完成文檔和圖片的處理。 2.了解Linux網絡管理的知識,熟悉Linux網絡配置的方法,掌握在Linux環境下配置Web服務器和ftp服務的方法。 二、實驗內容 1.配置Linux系統的網絡環境,安裝FTP和Web服務器,并配置相關的屬性,利用FTP實現WINDOWS和Linux之間的數據交換。 2.利用FTP程序上傳自己的照片到FTP服務器,利用OpenOffice的文字處理工具OpenOffice Writer制作一份表格形式的個人簡歷。個人簡歷中至少包含學號、姓名、性別、專業、照片和學習經歷等內容,并保存為網頁格式(html格式)。3.將個人簡歷網頁設置為WEB服務器的首頁,然后在客戶端利用瀏覽器訪問WEB服務器,查看效果。 4.通過讀取proc文件系統,獲取系統各種信息(如主機名、系統啟動時間、運行時間、版本號、所有進程信息、CPU使用率等),并以比較容易的方式顯示。 三、實驗過程及結果 1.配置網絡環境:在(服務.cmd).里面進行以下操作:在服務里選擇3按回車 完成后,可在本地連接看到VMware已連接上網絡 在虛擬機設置中設置以太網網絡連接方式為 網關地址填虛擬機的網管,IP地址設為虛擬機的一個子網: 四、總結: 在linux系統下,make是我們經常用到的編譯命令,所以關于make代碼和他的操作指令一定要記清楚。所以,熟練掌握了make和makefile工具之后,源碼安裝軟件就變的像windows下安裝軟件一樣簡單。 實驗四 進程控制與管理 一、實驗目的 1.掌握GCC編譯器的用法,學會利用GCC編輯器來編輯C語言程序,學會利用GDB調試器來調試C語言程序。 2.理解進程和程序的區別和聯系,3.掌握在Linux環境下觀察進程運行情況和CPU工作情況的命令。4.了解fork()系統調用,掌握利用fork()創建進程的方法。 5.了解Linux系統其他與進程相關的系統調用,如exec、wait和exit等。6.了解Linux常用的進程通信機制。 二、實驗內容 1.利用Linux的進程管理命令ps、top來監視和跟蹤進程,體會進程和程序的關系。2.利用Linux的文字編輯器編寫文件復制的C語言程序,并用gcc編譯該程序,然后運行該程序。 3.編寫一段程序,使用系統調用fork()創建兩個子進程。當此程序運行時,在系統中有一個父進程和兩個子進程活動。讓每一個進程在屏幕上顯示一個字符:父進程顯示'a',子進程分別顯示字符'b'和字符'c'。試觀察記錄屏幕上的顯示結果,并分析原因。 4.修改上述程序,每一個進程循環顯示一句話。子進程顯示'daughter ?'及'son ??',父進程顯示 'parent ??',觀察結果,分析原因。5.用fork()創建一個進程,再調用exec()用新的程序替換該子進程的內容。 三、實驗過程及結果 1、利用Linux的進程管理命令ps、top來監視和跟蹤進程,體會進程和程序的關系。<1>從用戶身份切換到ROOT身份 <2>輸入命令 ps 查看進程 <2>輸入命令 top 跟蹤進程 2、利用Linux的文字編輯器編寫一個計算機100個自然數和的C語言程序,并用gcc編譯該程序,然后運行該程序。 <1>創建一個.C文件 并進入進行編輯 <2>用GCC 進行編譯,再查看文件,發現產生執行文件 a.out <3>執行這個可執行文件得到結果5050 1、編寫一段程序,使用系統調用fork()創建兩個子進程。當此程序運行時,在系統中有一個父進程和兩個子進程活動。讓每一個進程在屏幕上顯示一個字符:父進程顯示'a',子進程分別顯示字符'b'和字符'c'。試觀察記錄屏幕上的顯示結果,并分析原因。 <1>穿件一個.C文件 并進行編寫程序代碼 <2>反復執行2次該程序 <3>可以看出兩次執行的結果 a b c 出現的順序不同,原因是,3個進程的輸出次序是隨機的,并不會按規定的順序出現,所以會出現上述結果。 4、修改上述程序,每一個進程循環顯示一句話。子進程顯示'daughter ?'及'son ??',父進程顯示 'parent ??',觀察結果,分析原因。<1>重新修改代碼 <3>執行這段程序 <4>原分析: 因和之前一樣,可以看出執行的結果 3個單詞出現的順序不同,原因是,3個進程的輸出次序是隨機的,并不會按規定的順序出現,所以會出現上述結果。 5、用fork()創建一個進程,再調用exec()用新的程序替換該子進程的內容。<1> 編寫代碼 <2> 執行的結果 結果表明 execl 替代了son的內容 四、實驗總結和體會 這個實驗考察的是進程之間存在很多可能性以及對編輯器的使用。本次實驗學習了在linux環境下用gcc編譯器運行c語言程序,在linux環境下編寫程序用到了vi編輯器,知道了該編輯器也需要各種命令來操作。編寫C語言程序時用到了fork()函數,再調用execl()用新的程序替換該子進程的內容。 實驗五 進程調度模擬程序的設計與實現 一、實驗目的 1.了解進程調度的概念,掌握常用進程調度算法的原理。2.掌握Linux程序設計編輯、編譯和調試的技巧。 二、實驗內容 1.編寫程序實現進程調度調度算法先來先服務、優先級高優先和時間片輪轉調度算法。(編程語言不限) 2.輸入數據,輸出運行結果。 三、實驗過程及結果 1先來先服務 #i nclude struct { int id; float ArriveTime;float RequestTime;float StartTime;float EndTime;float RunTime;float DQRunTime;int Status;}arrayTask[4];GetTask(){ int i;float a; for(i=0;i<4;i++){arrayTask[i].id=i+1;printf(“input the number”); printf(“input the the ArriveTime of arrayTask[%d]:”,i);scanf(“%f”,&a); arrayTask[i].ArriveTime=a; printf(“input the RequestTime of arrayTask[%d]:”,i);scanf(“%f”,&a); arrayTask[i].RequestTime=a;arrayTask[i].StartTime=0;arrayTask[i].EndTime=0;arrayTask[i].RunTime=0;arrayTask[i].Status=0; } } int fcfs() { int i,j,w=0; for(i=0;i<4;i++) { if(arrayTask[i].Status==0) { t=arrayTask[i].ArriveTime; w=1; } if(w==1) break; } for(i=0;i<4;i++) { if(arrayTask[i].ArriveTime t=arrayTask[i].ArriveTime; } for(i=0;i<4;i++) { if(arrayTask[i].ArriveTime==t) return i; } } int sjf(){ int i,x=0,a=0,b=0;float g; for(i=0;i<4;i++){ if(arrayTask[i].Status==1){g=arrayTask[i].EndTime;x=1;} } if(x==0){ t=arrayTask[0].ArriveTime; for(i=0;i<4;i++){ if(arrayTask[i].ArriveTime t=arrayTask[i].ArriveTime;a=i;} } return a;} else { for(i=0;i<4;i++){ if(arrayTask[i].EndTime>g)g=arrayTask[i].EndTime;} for(i=0;i<4;i++){ if(arrayTask[i].Status==0&& arrayTask[i].ArriveTime<=g){ t=arrayTask[i].RequestTime;a=i;b=1;} /*判斷有沒有進程在前個進程完成前到達*/ } if(b!=0)/*有進程到達則按SJF*/ { for(i=0;i<4;i++){ if(arrayTask[i].Status==0&&arrayTask[i].ArriveTime<=g&&arrayTask[i].RequestTime return a;} else{ /*否則按FCFS*/ for(i=0;i<4;i++) {if(arrayTask[i].Status==0)t=arrayTask[i].ArriveTime;} for(i=0;i<4;i++){ if(arrayTask[i].Status==0&&arrayTask[i].ArriveTime return a;} } } new(int s)/*定義執行進程后相關數據的修改*/ { int i,g=0;for(i=0;i<4;i++){ if(arrayTask[i].Status==0)continue;else { g=1;break;} } if(g==0)/*當處理的是第一個未執行的進程時執行*/ { arrayTask[s].StartTime=arrayTask[s].ArriveTime; arrayTask[s].EndTime=arrayTask[s].RequestTime+arrayTask[s].ArriveTime;arrayTask[s].RunTime=arrayTask[s].RequestTime;arrayTask[s].Status=1;g=2;} if(g==1)/*當處理的不是第一個未執行的進程時執行*/ { arrayTask[s].Status=1;for(i=0;i<4;i++){ if(arrayTask[i].Status==1)d=arrayTask[i].EndTime;} for(i=0;i<4;i++)/*查找最后執行的進程的完成時間*/ { if(arrayTask[i].EndTime>d&&arrayTask[i].Status==1)d=arrayTask[i].EndTime;} if(arrayTask[s].ArriveTime arrayTask[s].StartTime=arrayTask[s].ArriveTime; arrayTask[s].EndTime=arrayTask[s].StartTime+arrayTask[s].RequestTime;arrayTask[s].RunTime=arrayTask[s].EndTime-arrayTask[s].ArriveTime;} arrayTask[s].DQRunTime=arrayTask[s].RunTime/arrayTask[s].RequestTime;} Printresult(int j)/*定義打印函數*/ { printf(“%dt”,arrayTask[j].id); printf(“%5.2ft”,arrayTask[j].ArriveTime);printf(“%5.2ft”,arrayTask[j].RequestTime);printf(“%5.2ft”,arrayTask[j].StartTime);printf(“%5.2ft”,arrayTask[j].EndTime);printf(“%5.2ft”,arrayTask[j].RunTime);printf(“%5.2fn”,arrayTask[j].DQRunTime);} main(){ int i,b,k,a,c=0;int d[4];clrscr(); printf(“t F.FCFS n”);printf(“t S.SFJ n”);printf(“t Q.EXIT n”);for(i=0;;i++){ if(c)break; printf(“please input the number a:n”);scanf(“%d”,&a);switch(a){ case Q: c=1;break; case F:printf(“please input the different-ArriveTime of arrayTasksn”);GetTask(); printf(“*****************************the result of fcfsn”);printf(“NumbertArrivetServertStarttFinishtTurnovetTake power turnover timen”); for(b=0;b<4;b++)/*調用兩個函數改變結構體數的值*/ { k=fcfs();d[b]=k;new(k);} for(b=0;b<4;b++) Printresult(d[b]);/*調用打印函數打出結果*/ continue; case S: printf(“please input the different-RequestTime of array Tasksn”);GetTask(); printf(“******************************the result of sjfn”);printf(“NumbertArrivetRequesttStarttEndtRuntDQRun timen”);for(b=0;b<4;b++){ k=sjf();d[b]=k;new(k);} for(b=0;b<4;b++)Printresult(d[b]);continue; default:printf(“the number Error.please input another number!n”);} } } 四、實驗總結和體會 通過做本實驗,讓我對進程或作業先來先服務、高優先權、按時間片輪轉調度算法以及進程調度的概念和算法,有了更深入的認識!理解進程的狀態及變化,動態顯示每個進程的當前狀態及進程的調度情況。進程調度是處理機管理的核心內容。優先級高優先是根據作業的優先級,總是選擇優先級最高者進入隊列。輪轉調度算法是調度程序每次把CPU分配給就緒隊列首進程/線程使用規定的時間間隔,就緒隊列中都路保留巡行一個時間片。 一.實驗內容描述 1.目的 (1)了解Windows內存管理器(2)理解Windows的地址過程 2.內容 任意給出一個虛擬地址,通過WinDbg觀察相關數據并找到其物理地址 二.理論分析 Windows采用頁式虛擬存儲管理技術管理內存,頁面是硬件級別上的最小保護單位 1.Windows內存管理器 Windows的內存管理主要由Windows執行體中的虛存管理程序負責,并由環境子系統負責,并由環境子系統負責與具體API相關的一些用戶態特性的實現。虛存管理程序是Windows中負責內存管理的那些子程序和數據結構的集合 內存管理器的主要任務是: 地址變換:將一個進程的虛擬地址空間轉譯為物理內存地址 交換:當內存不足時,將內存中的有些內容轉移到磁盤上,并且以后還要再次將這些內容讀回 2.Windows內存管理策略 Windows采用頁式虛擬存儲管理技術管理內存,頁面是硬件級別上最小的保護單位。根據硬件的體系結構不同,頁面尺寸被分為兩種,大頁面和小頁面。X86系統下小頁面為4KB,大頁面為4MB。大頁面的優點是:當引用同一頁面內其他數據時,地址轉移的速度會很快。不過使用大頁面通常要較大的內存空間,而且必須用一個單獨的保護項來映射,因此可能會造成出現錯誤而不引發內存訪問違例的情況。通常PC機都為小頁面 3.Windows虛擬地址空間布局 x86結構下的布局方式: 默認情況下,32位Windows系統中每個用戶進程可以占有2GB的私有地址空間。操作系統占有另外的2GB 2GB用戶的進程地址空間布局如表: 2GB的系統地址空間布局如同: 3.虛擬地址轉譯 地址轉譯是指將進程的虛擬地址空間映射到實際物理頁面的過程。x86系統中地址轉譯過程如圖: 關鍵數據結構如下: 頁目錄:每個進程都有一個頁目錄,它是內存管理器為了映射進程中所有的頁表位置而創建的一個頁面。進程也目錄的地址被保存在內核進程快KPROCESS中,在x86系統上,它被映射到虛擬地址0xC0300000,當一個進程正在執行時,CPU可以通過寄存器CR3知道該進程頁目錄的位置。頁目錄由目錄項(PDE)構成,每個PDE長4字節,描述了該進程中所有可能的頁表的狀態和位置。其格式和PTE類似。x86系統上,要描述完整的4GB虛擬地址空間,需要1024個頁表。因此映射這些頁表的進程頁目錄需包含1024個PDE,恰好占用一個頁面。 頁表:進程的頁目錄項指向頁表。每個頁表占用一個頁面,由1024項PTE組成。一個有效的PTE大小為4字節,包含兩個主域:數據所在的物理頁面的頁面幀編號(PNF)或者內存中一個頁面的物理地址的PFN;一些描述該頁面狀態和保護屬性的標志。 虛擬地質結構:x86系統上,一個32位虛擬地址被解釋為三個單獨的部分,頁目錄索引、頁表索引和字節索引。由于頁目錄項有1024個,因此頁目錄索引為10位;一個也表中含有1024個PTE。因此頁表索引也為10位,字節索引為12位,正好表示一頁(4KB)內容 三.實驗步驟及結果 1.查找頁目錄首地址 以程序WG.exe作為觀測對象。 啟動WinDbg到內核調試模式,運行程序WG.exe。終斷目標機運行,輸入命令:kd>!process 發現WG.exe進程正處于運行狀態 輸入命令: 在KPROCESS中名為DirectoryTableBase的域,對應值為0x9fa6000,即WG.exe進程頁目錄的物理地址 查看CR3寄存其中的內容,輸入命令: CR3寄存其中的值和KPROCESS中記錄的頁目錄基址相同。這是因為在CPU切換執行任務時,其內容要更新為當前進程的頁目錄基址。2.地址轉譯過程 假設給定的虛擬地址為0x401001 輸入命令: 可以看到: PDE的虛擬地址為C0300004.PTE的虛擬地址為C0001004 最后一行信息“pfn 9e4a---DA--UWEV”表示PDE中的具體內容,9e4a是給定虛擬地址所在頁表在內存中對應的物理頁號,“---DA—UWEV”是標志信息,“pfn a173----A--UREV”表示PTE中的具體內容,a173是數據頁裝入內存的物理頁號。 將數據頁對應的物理頁號a173加上業內索引(0x1)即可得到虛擬地址0x401001的物理地址 3.觀察系統頁表 給定觀測虛擬地址為0x80001001 輸入命令: 當前正在執行的進程是:WG.exe 輸入命令: 得到PDE為C0300800,其對應的物理頁號為3b 繼續讓目標機運行,啟動A.exe,然后中斷目標機運行。輸入命令: 當前正在執行的進程為A.exe 輸入命令: PDE信息和對應的物理頁號與前面觀測到的相同 四.結論 1.數據頁對應的物理頁號加上相應業內索引即可得到虛擬地址的物理地址 2.不同的進程頁目錄都指向了相同的系統表頁 五.心得體會 在這次上機實驗,通過對WinDbg和VPc的調試運用,我熟悉了Windows內存管理器的結構,也認知到Windows如何進行地址轉譯和轉換。對相關的知識也進行了溫習,更牢的掌握了相關知識。當然這些還遠遠不夠,我以后還要繼續不斷努力,去學習了解掌握操作系統的各方面知識。 附錄: 1.A.exe代碼 #include #define N 1 HANDLE mutexSemaphore;HANDLE synchSemaphore_1;HANDLE synchSemaphore_2; HANDLE mutexDisplay; void Display(char*str,int delayTime){ if(WaitForSingleObject(mutexDisplay,INFINITE)==WAIT_OBJECT_0){ printf(“%snn”,str);ReleaseMutex(mutexDisplay);Sleep(delayTime);} } void useTime(double limit){ for(double i=0;i<=limit;i+=0.001);} void CreateProduct(){ Display(“Creating a production...”,0);useTime(200000);Display(“Creating finished.”,100);} void PutProduct(){ Display(“Putting a production...”,0);useTime(150000);Display(“Putting finished”,100);} void GetProduct(){ Display(“Getting a production...”,0);useTime(100000);Display(“Getting finished.”,100);} void ConsumeProduct(){ Display(“Cosuming a production...”,0);useTime(100000);Display(“Cosuming finished.”,100);} void Producer(){ while(true){ CreateProduct(); if(WaitForSingleObject(synchSemaphore_1,INFINITE)==WAIT_OBJECT_0){ if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0){ PutProduct();ReleaseSemaphore(mutexSemaphore,1,NULL);} ReleaseSemaphore(synchSemaphore_2,1,NULL);} } } void Consumer(){ while(true){ if(WaitForSingleObject(synchSemaphore_2,INFINITE)==WAIT_OBJECT_0){ if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0){ GetProduct();ReleaseSemaphore(mutexSemaphore,1,NULL);} ReleaseSemaphore(synchSemaphore_1,1,NULL);} ConsumeProduct();} } int main(){ HANDLE thread[2];DWORD threadID[2]; synchSemaphore_1=CreateSemaphore(NULL,N,N,NULL);synchSemaphore_2=CreateSemaphore(NULL,0,N,NULL);mutexSemaphore=CreateSemaphore(NULL,1,1,NULL); mutexDisplay=CreateMutex(NULL,FALSE,NULL); printf(“Program start.Please use WinDbg to observe main thread.nPress any key to continue...n”);getchar(); thread[0]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Producer),NULL,CREATE_SUSPENDED,&threadID[0]);printf(“A producer was created.Please use WinDbg to observe producer thread.nPress any key to continue...n”);getchar(); thread[1]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consumer),NULL,CREATE_SUSPENDED,&threadID[1]);printf(“A Consumer was created.Please use WinDbg to observe Consumer thread.nPress any key to continue...n”);getchar(); printf(“Please select:n[1]Make producer thread runn[2]Make Consumer thread runn”);bool flag=true;bool flag_1=true,flag_2=true;int count=0;while(flag){ if(getchar()=='1'&&flag_1){ ResumeThread(thread[0]);count++;flag_1=false;} else if(getchar()=='2'&&flag_2){ ResumeThread(thread[1]);count++;flag_2=false;} if(count==2)flag=false;} WaitForMultipleObjects(1,thread,TRUE,INFINITE); return 0;} 2.WG.exe代碼: #include int main(){ int a=0;printf(“I'm Wangn”);while(true){a++;} }第二篇:操作系統進程調度算法模擬實驗報告
第三篇:操作系統實驗報告
第四篇:操作系統實驗報告
第五篇:操作系統 單處理機系統的進程調度