作業系統實驗報告【新版多篇】
作業系統實驗報告 篇一
實驗二
程序排程
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->e=1; printf(“輸入就緒程序%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&p->,&p->_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->e=0; printf(“輸入阻塞程序%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&q->,&q->_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->,p->e,p->_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->e=2; printf(”程序%d排程t“,p->); state和 use_cpu++; x++; p->_time--; if(p->_time) { ready_tail->next=p; ready_tail=p; } else { printf(”程序%d完成t“,p->); 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 姓名:明章輝 指導教師:徐軍利 一、實驗目的 模擬檔案系統實現的基本功能,瞭解檔案系統的基本結構和檔案的各種管理方法,加深理解檔案系統的內部功能及內部實現。通過用高階語言編寫和除錯一個簡單的檔案系統,模擬檔案管理的工作過程,從而對各種檔案操作命令的實質內容和執行過程有比較深入的瞭解。 二、實驗內容和要求 程式設計模擬一個簡單的檔案系統,實現檔案系統的管理和控制功能。要求本檔案系統採用兩級目錄,即設定主檔案目錄[MFD]和使用者檔案目錄[UED]。另外,為開啟檔案設定執行檔案目錄[AFD]。設計一個10個使用者的檔案系統,每次使用者可儲存10個檔案,一次執行使用者可以開啟5個檔案,並對檔案必須設定保護措施。在使用者程式中通過使用檔案系統提供的Create、open、read、write、close、等檔案命令,對檔案進行操作 三、實驗主要儀器裝置和材料 硬體環境:IBM-PC或相容機 軟體環境:C語言程式設計環境 四、實驗原理及設計方案 1、實驗原理 運用二級目錄思想來模擬檔案系統。 為每個使用者建立一個單獨的使用者檔案目錄UFD。這些檔案目錄具有相似的結構,它由使用者檔案的檔案塊組成。此外,在系統再建立一個主檔案目錄MFD;在主檔案目錄中,每個使用者目錄都佔有一個目錄項,其目錄項中包含檔名和指向該檔案目錄檔案的指標。 3、程式流程圖 五、結果過程及截圖 系統的使用簡要說明: 登陸: create命令新建檔案 file5 Create失敗 命令刪除檔案 Delete失敗: open開啟命令,及write命令來追加檔案 Read命令和close命令關閉 對沒開啟的檔案讀寫: 六、所遇困難的解決以及心得體會 本實驗的程式碼長度的最常的,但是原理很簡單,並且實驗要求的是模擬,所以大大降低了實驗的難度,在作業系統課中我們還有一個課程設計,也是檔案管理系統,但是要比這個難很多,通過這個實驗,我對檔案管理系統的執行機制有了深入的瞭解,因為要做好這個實驗必須要懂得檔案管理系統的'架構,這也迫使我認認真真的研究了作業系統中關於檔案管理這一章的內容。同時這個程式也為以後的課程設計奠定了基礎,並且很多的程式碼也是可以重用的。 七、思考題 1、檔案系統要解決哪些問題? 答:要解決檔案和使用者是否同名,檔案建立數是否超額,所要求檔案是否存在等問題。 2、什麼是檔案目錄?什麼是檔案目錄中包含哪些資訊?目前廣泛採用的目錄結構形式是哪種? 答:檔案目錄就是用來展示一個使用者的所有檔案的一個表格,檔案目錄應包含檔名,保密碼,檔案大小,目前廣泛採用的目錄結構形式是多級目錄形式。 八、原始碼 #include #include #include #include #define NULL 0 typedef struct mdf{//MDF結構體 char username[20];//使用者名稱 char filename[20];//檔名 struct mdf *next; }MDF; typedef struct ufd{//UFD結構體 char filename[20];//檔名 int protect;//檔案保護碼 unsigned int length;//檔案長度 struct ufd *next; }UFD; typedef struct afd{//AFD結構體 char filename[20];//檔名 int protect;//檔案保護碼 unsigned int point;//檔案讀寫指標 struct afd *next; }AFD; MDF *pmdf;//全域性連結串列頭指標 UFD *pufd; AFD *pafd; char UserUFD[20];//已經登陸成功的使用者名稱 void initMDF()//初始化MDF表 { FILE *fp; pmdf= (MDF*)malloc(sizeof(MDF)); MDF *p = pmdf; if((fp = fopen( } exit(1); } while (!feof(fp)){//把MDF檔案中的內容裝入連結串列 } p->next = (MDF*)malloc(sizeof(MDF)); p = p->next; fscanf(fp, void printUFD()//列印MDF表 { UFD *p = pufd->next; puts( } void initUFD(char *name)//初始化UFD表 { FILE *fp; pufd= (UFD*)malloc(sizeof(UFD)); UFD *p = pufd; if((fp = fopen(name, } p->next = NULL; fclose(fp); int checkuser()//檢測登陸的使用者名稱 { } char username[20]; while(1){ puts( void initAFD()//初始化AFD { pafd = (AFD*)malloc(sizeof(AFD)); pafd->next = NULL; } bool create()//建立檔案命令 { char filename[20]; UFD *p = pufd->next; AFD *pa = pafd; puts( } } if(!p->next) break; p= p->next; p->next = (UFD*)malloc(sizeof(UFD)); p=p->next; strcpy(p->filename, filename); p->protect = 2; p->length = 0; p->next = NULL; while(pa->next){//建立檔案後加入到AFD } pa=pa->next; pa->next = (AFD*)malloc(sizeof(AFD)); pa = pa->next; strcpy(pa->filename ,filename); pa->protect = 2; pa->point = 0; pa->next = NULL; return 1; } bool _()//刪除檔案命令 { char filename[20]; puts( puts( return 0; } bool open()//開啟檔案命令 { char filename[20]; unsigned int protect; puts( } } puts( void close()//關閉檔案命令 { char filename[20]; UFD *pu = pufd->next; puts( int read()//讀檔案命令 { char filename[20]; unsigned int length; AFD *p = pafd->next; } puts( int write()//寫檔案命令 { } char filename[20]; unsigned int length; AFD *p = pafd->next; puts( void destroy()//釋放記憶體 { } void saveUFD()//儲存UFD檔案 { } void bye()//推出系統 { FILE *fp; UFD *p = pufd->next; if((fp = fopen(UserUFD, UFD *pu = pufd->next; while(pa){ if(pa->protect == 2){ while(pu){ } saveUFD(); printUFD(); destroy(); } } if(strcmp(pa->filename, pu->filename) == 0){ } pu->length = pa->point; break; pu = pu->next; pa =pa->next; } void operate()//命令識別 { while(1){ char command[20]; char name[][8] = { } } return; }else puts( void print() { puts( int main() { } print(); initMDF(); checkuser(); initAFD(); operate();)//命令識別 return 0; 實驗專案二 程序管理 一、實驗目的 1、理解程序的概念,掌握父、子程序建立的方法。 2、認識和了解併發執行的實質,掌握程序的併發及同步操作。 二、實驗內容 1、編寫一C語言程式,實現在程式執行時通過系統呼叫fork( )建立兩個子程序,使父、子三程序併發執行,父親程序執行時螢幕顯示“I am father”,兒子程序執行時螢幕顯示“I am son”,女兒程序執行時螢幕顯示“I am daughter”。 2、多次連續反覆執行這個程式,觀察螢幕顯示結果的順序,直至出現不一樣的情況為止。記下這種情況,試簡單分析其原因。 3、修改程式,在父、子程序中分別使用wait()、exit()等系統呼叫“實現”其同步推進,並獲取子程序的ID號及結束狀態值。多次反覆執行改進後的程式,觀察並記錄執行結果。 三、源程式及執行結果 源程式1: #include printf(“error!”); else if( pid == 0 ) { printf(“I am son!n”); } else { int pid=fork(); if (pid<0) printf(“error!”); else if( pid == 0 ) { printf(“I am daughter! n“); } else printf(”I am father!n“); } sleep(1); return 0; } 執行結果: 源程式2: #include int pid=fork(); if(pid<0) printf(”error!“); else if( pid == 0 ) { message=”I am daughter!“; pid=getpid(); n=3; } else { int pid=fork(); if (pid<0) printf(”error!“); else if( pid == 0 ) { message=”I am son!“; pid=getpid(); n=3; } else message=”I am father!"; n=3; } for(;n>0;n--) { puts(message); sleep(1); } return 0; } 執行結果: 四、實驗分析與總結 1、實驗內容1執行結果為什麼無固定順序,fork()函式建立程序是如何併發執行的。 答:因為程序是併發執行的,fork()函式建立的三個程序搶佔 cpu不同,從而導致三個程式被cpu 排程順序不同,所以實驗一結果無固定順序。Fork()函式呼叫成功後,子程序與父程序併發執行的程式碼相同,但由於子程序也繼承父程序的程式指標,所以子程序是從fork()後執行的,另外fork在子程序和父程序中返回值是不同的。在父程序中返回子程序的pid,而在子程序中返回0,使父程序和子程序執行不同的分支。 2、實驗內容3是如何實現父子程序的同步執行的。 答:wait()會暫時停止目前程序的執行,直到有訊號來到或子程序結束。程式段主要使用了函式wait()和,exit()這是因為父程序必須等待兩個子程序終止後才終。在父程序中呼叫wait()函式,則父程序被阻塞,進入等待佇列,等待子程序結束。子程序終止時執行exit()向父程序發終止訊號,當接到訊號後,父進提取子程序的結束狀態值,從wait()返回繼續執行原程式,從而實現了父、子程序的同步推進。 總結:通過程序管理實驗,瞭解fork()函式建立程序是併發執行的,wait()程序表示會暫時停止目前程序的執行,可以靈活運用fork()和wait()程序解決有關問題。在實驗中遇到許多問題,如:實驗中呼叫fork()程序失敗,可能的原因有系統中有太多的程序或者實際使用者ID的程序總數超過了系統的限制。剛接觸VMware這個系統,操作不熟悉,多次操作後,瞭解這個系統有關操作,實驗做起來就比較簡單了。對實驗程式碼也不熟悉,最後通過請教老師和同學,終於實驗理解透徹,併成功運行了。不僅上課要認真聽課,要想真正學會,課下也要付出努力。 實驗一 嵌入式開發環境的建立 一、實驗目的 通過此實驗系統,讀者可以瞭解嵌入式實時作業系統 uC/OS-II 的核心機制和執行原理。本實驗系統展示了 uC/OS-II 各方面的管理功能,包括訊號量、佇列、記憶體、時鐘等。在各個實驗中具體介紹了 uC/OS-II 的相關函式。讀者在做實驗的同時能夠結合理論知識加以分析,瞭解各個函式的作用和嵌入式應用程式的設計方法,最終對整個 uC/OS-II 和嵌入式作業系統的應用有較為清楚的認識。 二、實驗步驟 1、安裝整合開發環境LambdaEDU 整合開發環境LambdaEDU 的安裝資料夾為 LambdaEDU ,其中有一個名為“” 的檔案,直接雙擊該檔案便可啟動安裝過程。具體的安裝指導請看“LambdaEDU 安裝手 冊。doc”檔案。 當 LambdaEDU 安裝完畢之後,我們看到的是一個空的介面,現在就開始一步一步地將 我們的實驗專案建立並執行起來。 2、建立專案 為了我們的實驗執行起來,需要建立1 個專案基於x86 虛擬機器的標準應用專案。通過點 擊“檔案”、“新建”、“專案”開始根據嚮導建立一個專案。 在隨後出現的對話方塊中選擇“Tool/標準應用專案”,點選下一步,開始建立一個標準的 可執行的應用程式專案。 在隨後出現的對話方塊中填入專案名稱“ucos_x86_demo”。點選“下一步”。 選擇“pc386 uC/OS-II 應用(x86)”作為該專案的應用框架。點選“下一步” 選擇“pc386_elf_tra_debug”作為該專案的基本配置。點選“完成”。 新建立的專案“ucos_x86_demo”將會被新增到專案列表。src 資料夾下儲存了該專案中 包含的原始檔。ucos2 資料夾中包含了移植到x86 虛擬機器的全部程式碼。init.c 檔案是基於ucos2 和本虛擬機器的一個應用程式。在進行ucos2 核心實驗中,只需要替換init.c 檔案,即可。文 件名不限,但是檔名中最好不要使用英文符號和數字以外的其他字元, 3. 構建專案 到這裡,專案配置全部完成。接下來就可以進行構建專案了。 第一次構建本專案,在此專案上點選右鍵,選擇“重建BSP 及專案”。即可開始構建。 之後彈出的對話方塊顯示了構建的進度。可以點選“在後臺執行”,以隱藏該對話方塊 在構建的同時,在右下角的“構建資訊”檢視輸出構建過程中的詳細資訊: 注:“重新構建”將本專案中的全部原始碼進行一次完全的編譯和連線,花費時間較多。 “構建專案”則僅僅將新修改過的原始碼進行編譯和連線,花費時間最少。“重建BSP及項 目”,不但要完成“重新構建”的全部工作,另外還要編譯與該專案有關的的LambdaEDU 中內建的部分程式碼,花費時間最多。但是在專案剛建立後,第一次構建時需要選擇“重建 BSP 及專案”。以後的構建中選擇“重新構建”或“構建專案”即可。另外,在替換了源代 碼中的檔案後,需要選擇“重新構建”來完成該專案的構建。 4、配置虛擬機器和目標機代理 (1) 製作X86啟動盤 在 LambdaEDU 中依次點選“工具”、“Bochs”、“製作虛擬機器啟動映象”。 對啟動盤進行一些引數設定後(如下圖所示),系統將自動為你生成一個PC 虛擬機器的 啟動盤映像。 (2) 配置虛擬機器 選擇使用的網路介面卡(網絡卡)後,點選“確定”完成配置。 注意:如果計算機上有多網絡卡,請將其他網絡卡停用(包括 VMware 虛擬機器新增的虛擬 網絡卡)。 (3) 建立目標機代理 配置好虛擬機器後,建立目標機代理:點選LambdaEDU 左下方視窗中綠色的十字元號, 在彈出的視窗中選擇“基於TA 的連線方式”,並點選“下一步”。 在彈出的“新目標機連線配置中”的這些引數,應該與之前製作啟動盤時設定的引數一致。 注意: 名字:輸入目標機的名字(預設是 default),注意如果和現有目標機重名的話,改個名 字。 連線型別:預設選擇 UDP IP地址:這裡輸入目標機(在本實驗系統中是虛擬機器)的 IP地址; 最後點選“確定”,在目標機管理視窗中,可以看到新增加了一個名為default 的目標機 節點 (4) 除錯應用 啟動虛擬機器。 虛擬機器啟動後的畫面如下(其中顯示的IP 地址建立虛擬機器啟動盤時填入的IP 地址)中設定的IP 地址): 在成功完成構建的專案ucos_x86_demo 中的“pc386_elf_tra_debug”上點選滑鼠右鍵,在彈出的選單中選擇“除錯”,啟動偵錯程式除錯生成的程式: 第一次進行除錯/執行,需要選擇目標機,如下圖,選擇“Default”,點選“確定”,開 始向目標機(虛擬機器)下載應用程式。 程式下載完成後,會彈出一個“確認透檢視切換”對話方塊,選擇“是”,切換到除錯透 檢視。 除錯的介面如下: 點選綠色的按鈕,全速執行。 注意:全速執行後,程式不能夠被暫停和停止。 三、實驗過程中遇到的問題及體會 在設定IP地址時,要求該IP地址與本計算機在同一個子網中,同時要求該 IP地址沒有被網路上其他計算機使用。此外,通過構建開發環境,處次體驗到了嵌入式開發工作的樂趣。 實驗二 任務的基本管理 一、實驗目的 1、理解任務管理的基本原理,瞭解任務的各個基本狀態及其變遷過程; 2.掌握 uC/OS-II 中任務管理的基本方法(建立、啟動、掛起、解掛任務); 3. 熟練使用 uC/OS-II 任務管理的基本系統呼叫。 二、實驗原理及程式結構 1、實驗設計 為了展現任務的各種基本狀態及其變遷過程,本實驗設計了 Task0、Task1 兩個任務: 任務 Task0 不斷地掛起自己,再被任務 Task1 解掛,兩個任務不斷地切換執行。通過本實驗,讀者可以清晰地瞭解到任務在各個時刻的狀態以及狀態變遷的原因。 2. 執行流程 描述如下: (1)系統經歷一系列的初始化過程後進入 boot_card()函式,在其中呼叫 ucBsp_init()進 行板級初始化後,呼叫 main()函式; (2)main()函式呼叫 OSInit()函式對 uC/OS-II 核心進行初始化,呼叫 OSTaskCreate 創 建起始任務 TaskStart; (3)main()函式呼叫函式 OSStart()啟動 uC/OS-II 核心的執行,開始多工的排程,執 行當前優先順序最高的就緒任務 TaskStart; (4)TaskStart 完成如下工作: a、安裝時鐘中斷並初始化時鐘,建立 2 個應用任務; b、掛起自己(不再被其它任務喚醒),系統切換到當前優先順序最高的就緒任務Task0。之後整個系統的執行流程如下: t1 時刻,Task0 開始執行,它執行到 t2 時刻掛起自己; t2 時刻,系統排程處於就緒狀態的優先順序最高任務 Task1 執行,它在 t3 時刻喚醒Task0,後者由於優先順序較高而搶佔 CPU; Task0 執行到 t4 時刻又掛起自己,核心排程 Task1 執行; Task1 執行至 t5 時刻再度喚醒 Task0; …… 3、µC/OS-Ⅱ中的任務描述 一個任務通常是一個無限的迴圈,由於任務的執行是由作業系統核心排程的,因此任務是絕不會返回的,其返回引數必須定義成 void。在μC/OS-Ⅱ中,當一個執行著的任務使一個比它優先順序高的任務進入了就緒態,當前任務的 CPU 使用權就會被搶佔,高優先順序任務會立刻得到 CPU 的控制權(在系統允許排程和任務切換的前提下)。μC/OS-Ⅱ可以管理多達 64 個任務,但目前版本的μC/OS-Ⅱ有兩個任務已經被系統佔用了(即空閒任務和統計任務)。必須給每個任務賦以不同的優先順序,任務的優先順序號就是任務編號(ID),優先順序可以從 0 到 OS_LOWEST_PR10-2。優先順序號越低,任務的優先順序越高。μC/OS-Ⅱ總是執行進入就緒態的優先順序最高的任務。 4. 源程式說明 (1) TaskStart任務 TaskStart 任務負責安裝作業系統的時鐘中斷服務例程、初始化作業系統時鐘,並建立所 有的應用任務: UCOS_CPU_INIT(); /* Install uC/OS-II's clock tick ISR */ UCOS_TIMER_START(); /*Timer 初始化*/ TaskStartCreateTasks(); /* Create all the application tasks */ OSTaskSuspend(OS_PRIO_SELF); 具體負責應用任務建立的 TaskStartCreateTasks 函式程式碼如下,它建立了兩個應用任務 Task0 和 Task1: void TaskStartCreateTasks (void) { INT8U i; for (i = 0; i TaskData[i] = i; // Each task will display itsown information } OSTaskCreate(Task0, (void *)&TaskData[0], &TaskStk[0][TASK_STK_SIZE1], 6); } TaskStart 任務完成上述操作後將自己掛起,作業系統將排程當前優先順序最高的應用任務Task0 執行。 (2) 應用任務 應用任務 Task0 執行後將自己掛起,之後作業系統就會排程處於就緒狀態的優先順序最高的任務,具體程式碼如下: void Task0 (void *pdata) { INT8U i; INT8U err; i=*(int *)pdata; for (;;) { printf(“Application tasks switched %d times!nr”,++count); printf(“TASK_0 IS RUNNING.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。nr”); printf(“task_1 is suspended!nr”); printf(“**************************************************nr”); err=OSTaskSuspend(5); // suspend itself } } 應用任務 Task1 執行後將 Task0 喚醒,使其進入到就緒佇列中: void Task1 (void *pdata) { INT8U i; INT8U err; i=*(int *)pdata; for (;;) { OSTimeDly(150); printf(“Application tasks switched %d times!nr”,++count); printf(“task_0 is suspended!nr”); printf(“TASK_1 IS RUNNING.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。.。nr”); printf(“**************************************************nr”); OSTimeDly(150); err=OSTaskResume(5); /* resume task0 */ } } 三、執行及觀察應用輸出資訊 按照本實驗手冊第一部分所描述的方法建立應用專案並完成構建 ,當我們在 LambdaEDU 偵錯程式的控制下執行構建好的程式後,將看到在μC/OS-Ⅱ核心的排程管理下, 兩個應用任務不斷切換執行的情形: 四、本實驗中用到的µC/OS-Ⅱ相關函式 4.1 OSTaskCreate() OSTaskCreate()建立一個新任務。任務的建立可以在多工環境啟動之前,也可以在 正在執行的任務中建立。中斷處理程式中不能建立任務。一個任務必須為無限迴圈結構,且 不能有返回點。 OSTaskCreate()是為與先前的μC/OS 版本保持相容,新增的特性在 OSTaskCreateExt ()函式中。 無論使用者程式中是否產生中斷,在初始化任務堆疊時,堆疊的結構必須與 CPU 中斷後 暫存器入棧的順序結構相同。詳細說明請參考所用處理器的手冊。 函式原型: INT8U OSTaskCreate( void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio ); 引數說明: task 是指向任務程式碼首地址的指標。 pdata 指向一個資料結構,該結構用來在建立任務時向任務傳遞引數。 ptos 為指向任務堆疊棧頂的指標。任務堆疊用來儲存區域性變數,函式引數,返回地址 以及任務被中斷時的 CPU 暫存器內容。任務堆疊的大小決定於任務的需要及預計的中斷嵌 套層數。計算堆疊的大小,需要知道任務的區域性變數所佔的空間,可能產生巢狀呼叫的函式,及中斷巢狀所需空間。如果初始化常量 OS_STK_GROWTH 設為 1,堆疊被設為從記憶體高地址 向 低 地 址 增 長 , 此時 ptos 應 該 指 向任 務堆 棧 空 間 的 最 高 地 址 。 反 之 , 如 果OS_STK_GROWTH 設為 0,堆疊將從記憶體的低地址向高地址增長。prio 為任務的優先順序。每個任務必須有一個唯一的優先順序作為標識。數字越小,優先順序越高。 返回值: OSTaskCreate()的返回值為下述之一: OS_NO_ERR:函式呼叫成功。 OS_PRIO_EXIST:具有該優先順序的任務已經存在。 OS_PRIO_INVALID:引數指定的優先順序大於 OS_LOWEST_PRIO。 OS_NO_MORE_TCB:系統中沒有 OS_TCB 可以分配給任務了。 注意: 任務堆疊必須宣告為 OS_STK 型別。 在任務中必須呼叫μC/OS 提供的下述過程之一:延時等待、任務掛起、等待事件發生 (等待訊號量,訊息郵箱、訊息佇列),以使其他任務得到 CPU。 用 戶 程 序 中 不 能 使 用 優 先 級 0 , 1 , 2 , 3 , 以 及 OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。這些優先順序μC/OS 系統 保留,其餘的 56 個優先順序提供給應用程式。 4.2 OSTaskSuspend() OSTaskSuspend () 無條件掛起一個任務 。呼叫此函式的任務也可以傳遞引數 OS_PRIO_SELF,掛起呼叫任務本身。當前任務掛起後,只有其他任務才能喚醒。任務掛起 後,系統會重新進行任務排程,執行下一個優先順序最高的就緒任務。喚醒掛起任務需要呼叫 函式 OSTaskResume ()。 任務的掛起是可以疊加到其他操作上的。例如,任務被掛起時正在進行延時操作,那麼 任務的喚醒就需要兩個條件:延時的結束以及其他任務的喚醒操作。又如,任務被掛起時正 在等待訊號量,當任務從訊號量的等待對列中清除後也不能立即執行,而必須等到被喚醒後。 函式原型: INT8U OSTaskSuspend( INT8U prio); 引數說明: prio 為指定要獲取掛起的任務優先順序,也可以指定引數 OS_PRIO_SELF,掛起任務本 身。此時,下一個優先順序最高的就緒任務將執行。 返回值: OSTaskSuspend()的返回值為下述之一: OS_NO_ERR:函式呼叫成功。 OS_TASK_ SUSPEND_IDLE:試圖掛起 µC/OS-II 中的空閒任務(Idle task)。此為非法操作。 16 OS_PRIO_INVALID :引數指定的優先順序大於 OS_LOWEST_PRIO 或沒有設定 OS_PRIO_SELF 的值。 OS_TASK_ SUSPEND _PRIO:要掛起的任務不存在。 注意: 在程式中 OSTaskSuspend()和 OSTaskResume ()應該成對使用。 用 OSTaskSuspend()掛起的任務只能用 OSTaskResume ()喚醒。 4.3 OSTaskResume() OSTaskResume ()喚醒一個用 OSTaskSuspend()函式掛起的任務。OSTaskResume ()也是唯一能“解掛”掛起任務的函式。 函式原型: INT8UOSTaskResume ( INT8U prio); 引數說明: prio 指定要喚醒任務的優先順序。 返回值: OSTaskResume ()的返回值為下述之一: OS_NO_ERR:函式呼叫成功。 OS_TASK_RESUME_PRIO:要喚醒的任務不存在。 OS_TASK_NOT_SUSPENDED:要喚醒的任務不在掛起狀態。 OS_PRIO_INVALID:引數指定的優先順序大於或等於 OS_LOWEST_PRIO。 五、實驗過程中遇到的問題及體會 實驗過程中體會到了嵌入式開發的樂趣,對上課老師所講的內容有了進一步的認識與理解。 17 實驗三 訊號量:哲學家就餐問題的實現 一、實驗目的 掌握在基於嵌入式實時作業系統 uC/OS-II 的應用中,任務使用訊號量的一般原理。通 過經典的哲學家就餐實驗,瞭解如何利用訊號量來對共享資源進行互斥訪問。 二、實驗原理及程式結構 1、實驗設計 掌握在基於嵌入式實時作業系統 uC/OS-II 的應用中,任務使用訊號量的一般原理。通 過經典的哲學家就餐實驗,瞭解如何利用訊號量來對共享資源進行互斥訪問。 2. 源程式說明 五個哲學家任務(ph1、ph2、ph3、ph4、ph5)主要有兩種過程:思考(即睡眠一段時 間)和就餐。每個哲學家任務在就餐前必須申請並獲得一左一右兩支筷子,就餐完畢後釋放 這兩支筷子。五個哲學家圍成一圈,每兩人之間有一支筷子。一共有五支筷子,在該實驗中 用了五個互斥訊號量來代表。每個任務的程式碼都一樣,如下所示: void Task (void *pdata) { INT8U err; INT8U i; INT8U j; i=*(int *)pdata; j=(i+1) % 5; uC/OS-II 實驗指導書 for (;;) { TaskThinking2Hungry(i); OSSemPend(fork[i], 0, &err); OSSemPend(fork[j], 0, &err); /* Acquire semaphores to eat */ TaskEat(i); OSSemPost(fork[j]); OSSemPost(fork[i]); /* Release semaphore */ OSTimeDly(200); /* Delay 10 clock tick */ } } 作業系統配置 修改 uC_OS-II/OS_CFG.h: :: : #define OS_MAX_EVENTS 10 /*最多可以有 10 個事件*/ #define OS_MAX_FLAGS 5 /*最多可以有 5 個事件標誌*/ #define OS_MAX_MEM_PART 5 /*最多可以劃分 5 個記憶體塊*/ #define OS_MAX_QS 2 /*最多可以使用 2 個佇列*/ #define OS_MAX_TASKS 8 /*最多可以建立 8 個任務*/ #define OS_LOWEST_PRIO 14 /*任務優先順序不可以大於 14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空閒任務堆疊大小*/ #define OS_TASK_STAT_EN 1 /*是否允許使用統計任務*/ #define OS_TASK_STAT_STK_SIZE 1024 /*統計任務堆疊大小*/ #define OS_FLAG_EN 1 /*是否允許使用事件標誌功能*/ #define OS_FLAG_WAIT_CLR_EN 1 /*是否允許等待清除事件標誌*/ #define OS_FLAG_ACCEPT_EN 1 /*是否允許使用 OSFlagAccept()*/ #define OS_FLAG_DEL_EN 1 /*是否允許使用 OSFlagDel()*/ #define OS_FLAG_QUERY_EN 1 /*是否允許使用 OSFlagQuery()*/ #define OS_MBOX_EN 0 /*是否允許使用郵箱功能*/ #define OS_MEM_EN 0 /*是否允許使用記憶體管理的功能*/ #define OS_MUTEX_EN 0 /*是否允許使用互斥訊號量的功能*/ #define OS_Q_EN 0 /*是否允許使用佇列功能*/ #define OS_SEM_EN 1 /*是否允許使用訊號量功能*/ #define OS_SEM_ACCEPT_EN 1 /*是否允許使用 OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允許使用OSSemDel() */ #define OS_SEM_QUERY_EN 1 /*是否允許使用OSSemQuery()*/ #define OS_TASK_CHANGE_PRIO_EN 1 /* 是 否 允 許 使 用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允許使用 OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允許使用 OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允許使用 OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /* 是 否 允 許 使 用 OSTaskSuspend() and OSTaskResume()*/ #define OS_TASK_QUERY_EN 1 /*是否允許使用 OSTaskQuery()*/ #define OS_TIME_DLY_HMSM_EN 1 /* 是 否 允 許 使 用 OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /* 是 否 允 許 使 用 OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /* 是否允許使用 OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /* 是 否 允 許 使 用 OSSchedLock() 和 OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*設定每秒之內的時鐘節拍數目*/ 三、執行及觀察應用輸出資訊 開始,所有的哲學家先處於 thinking 狀態,然後都進入 hungry 狀態: 後首先獲得兩個訊號量的 1、3 號哲學家開始 eating,待他們釋放相關訊號量之後,哲 學家 2、5、4 獲得所需的訊號量並 eating: 應用如此這般地迴圈執行程式下去„„ 19 四、本實驗中用到的µC/OS-Ⅱ相關函式 4.1 OSSemCreate() OSSemCreate()函式建立並初始化一個訊號量。訊號量的作用如下: 允許一個任務和其他任務或者中斷同步 取得裝置的使用權 標誌事件的發生 函式原型: OS_EVENT *OSSemCreate( (( (WORD value) )) ) 引數說明: value 引數是所建立的訊號量的初始值,可以取 0 到 65535 之間的任何值。 返回值: OSSemCreate()函式返回指向分配給所建立的訊號量的控制塊的指標。如果沒有可用的 控制塊,OSSemCreate()函式返回空指標。 注意: 必須先建立訊號量,然後使用。 4.2 OSSemPend() OSSemPend()函式用於任務試圖取得裝置的使用權,任務需要和其他任務或中斷同 步,任務需要等待特定事件的發生的場合。如果任務呼叫 OSSemPend()函式時,訊號量 的值大於零,OSSemPend()函式遞減該值並返回該值。如果呼叫時訊號量等於零, OSSemPend()函式函式將任務加入該訊號量的等待佇列。OSSemPend()函式掛起當前 任務直到其他的任務或中斷置起訊號量或超出等待的預期時間。如果在預期的時鐘節拍內信 號量被置起,μC/OS-Ⅱ預設最高優先順序的任務取得訊號量恢復執行。一個被 OSTaskSuspend ()函式掛起的任務也可以接受訊號量,但這個任務將一直保持掛起狀態直到通過呼叫 OSTaskResume()函式恢復任務的執行。 函式原型: :: : Void OSSemPend ( OS_EVNNT *pevent, INT16U timeout, int8u *err ); 引數說明: :: : pevent 是指向訊號量的指標。該指標的值在建立該訊號量時可以得到。( 參考 OSSemCreate()函式)。 Timeout 允許一個任務在經過了指定數目的時鐘節拍後還沒有得到需要的訊號量時 恢復就緒狀態。如果該值為零表示任務將持續地等待訊號量,最大的等待時間為 65535 個時 鍾節拍。這個時間長度並不是非常嚴格的,可能存在一個時鐘節拍的誤差。 Err 是指向包含錯誤碼的變數的指標。OSSemPend()函式返回的錯誤碼可能為下述幾 種: OS_NO_ERR :訊號量不為零。 OS_TIMEOUT :訊號量沒有在指定數目的時鐘週期內被設定。 OS_ERR_PEND_ISR :從中斷呼叫該函式。雖然規定了不允許從中斷呼叫該函式, 但 µC/OS-Ⅱ仍然包含了檢測這種情況的功能。 OS_ERR_EVENT_TYPE :pevent 不是指向訊號量的指標。 返回值: 無 注意: 必須先建立訊號量,然後使用。 不允許從中斷呼叫該函式。 4.3 OSSemPost() OSSemPost()函式置起指定的訊號量。如果指定的訊號量是零或大於零,OSSemPost () 函式遞增該訊號量並返回。如果有任何任務在等待訊號量,最高優先順序的任務將得到信 號量並進入就緒狀態。任務排程函式將進行任務排程,決定當前執行的任務是否仍然為最高 優先順序的就緒狀態的任務。 函式原型: INT8U OSSemPost(OS_EVENT *pevent); 引數說明: pevent 是指向訊號量的指標。該指標的值在建立該訊號量時可以得到。( 參考 OSSemCreate()函式)。 返回值: OSSemPost()函式的返回值為下述之一: OS_NO_ERR :訊號量被成功地設定 OS_SEM_OVF :訊號量的值溢位 OS_ERR_EVENT_TYPE :pevent 不是指向訊號量的指標 注意: 必須先建立訊號量,然後使用。 4.4 OSTimeDly() OSTimeDly()將一個任務延時若干個時鐘節拍。如果延時時間大於 0,系統將立即進 行任務排程。延時時間的長度可從 0 到 65535 個時鐘節拍。延時時間 0 表示不進行延時,函 21 數將立即返回呼叫者。延時的具體時間依賴於系統每秒鐘有多少時鐘節拍(由檔案 SO_CFG.H 中的常量 OS_TICKS_PER_SEC 設定)。 函式原型: void OSTimeDly ( INT16U ticks); 引數說明: ticks 為要延時的時鐘節拍數。 返回值: 無 注意: 注意到延時時間 0 表示不進行延時操作,而立即返回呼叫者。為了確保設定的延時時間, 建議使用者設定的時鐘節拍數加 1。例如,希望延時 10 個時鐘節拍,可設定引數為 11。 五、實驗過程中遇到的問題及體會 在實驗前要對該問題進行深入的理解,即五個哲學家任務(ph1、ph2、ph3、ph4、ph5)主要有兩種過程:思考(即睡眠一段時間)和就餐。每個哲學家任務在就餐前必須申請並獲得一左一右兩支筷子,就餐完畢後釋放這兩支筷子。五個哲學家圍成一圈,每兩人之間有一支筷子。只有理解了,才能更好的進行實驗。 22 1.實習目的 (一).通過綜合實訓進一步鞏固、深化和擴充套件學生的專業技能。 1.熟練掌握Linux作業系統的安裝及基本配置。 2.熟練掌握Linux系統管理。 3.掌握Linux下使用者和組的管理。 4.掌握Linux下FTP伺服器的管理。 (二)訓練和培養學生獲取資訊和處理資訊的能力,充分培養和提高學生的動手能力,學會通過網站、書籍等方式收集所需的。資料。 (三)培養學生運用所學的知識和技能解決Linux使用、管理過程中所遇到的實際問題的能力及其基本工作素質。 (四)培養學生理論聯絡實際的工作作風、嚴肅認真的科學態度以及獨立工作的能力,樹立自信心。 (五)訓練和培養學上的團隊協作精神與合作能力。 2 實習概況 2.1 實習要求 具體來講,《linux作業系統》課程包括以下實習內容: (一)獨立完成實訓。 (二)要求熟練掌握Linux作業系統的安裝與基本配置。 (三)熟練掌握Linux系統管理基本方法。 (四)掌握Linux下使用者和組的管理。。 (五)掌握Linux下的FTP伺服器的管理。 2.2 實習時間 20XX年12月16日至20XX年12月20日 2.3 實習基本情況 實習地點:四教學樓 4112、4212、4312、4412 實習環境 :RedHat9軟體 實習內容:掌握linux作業系統 2.4 硬體環境 3 實習內容 3.1 linux安裝 Linux是一類Unix計算機作業系統的統稱。Linux 是以Unix 作業系統為原型的多工、多使用者的系統。可運行於多種硬體平臺:PC、Alpha、SPARC、 POWER PC。 今天實習的主要內容是學習瞭解Linux的安裝過程;Linux登入和退出 ,熟悉Linux作業系統的圖形介面 (一)Linux的安裝過程 1)VMware軟體的安裝 因為我用的是機房的電腦,所以不用安裝VMware軟體。如果要安裝,過程十分簡單,下載完畢,直接“Next”即可完成安裝。 2)虛擬機器的安裝。開啟VMware軟體,單擊“新建虛擬機器”命令根據提示選擇一種要安裝的作業系統,一般選擇典型設定,然後直接按“下一步”即可。需要注意的就是在分割槽的時候需按要求建立合適的分割槽,如下圖所示。 圖3-1-1 選擇分割槽 3)Red Hat Linux 9.0安裝 首先單擊“編輯虛擬機器設定”,改寫映象為“linux9cd1”,然後返回初始介面。點選“啟動該虛擬機器”,便進入到軟體的安裝過程。開始是“歡迎使Red Hat Linux”介面,然後經歷語言選擇、鍵盤配置、滑鼠配置、磁碟分割槽設定、選擇軟體包組、安裝軟體包等操作後,然後是虛擬機器安裝完第一張盤後要進行第二張盤的安裝,如圖3-2經過老師的指點,按住“Ctrl+Alt”,將滑鼠調出,雙擊右下方工作列第一個按鈕,依次選擇第二、三映象,繼續安裝,便安裝成功了。如圖3-3。作業系統實驗報告 篇二
作業系統實驗報告 篇三
嵌入式作業系統實驗報告 篇四
作業系統實驗報告 篇五