實驗一 嵌入式開發環境的建立
一、實驗目的
通過此實驗系統,讀者可以瞭解嵌入式實時操作系統 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。 一、實驗目的 本實驗要求學生模擬作業調度的實現,用高級語言編寫和調試一個或多個作業調度的模擬程序,瞭解作業調度在操作系統中的作用,以加深對作業調度算法的理解。 二、實驗內容和要求 1、編寫並調度一個多道程序系統的作業調度模擬程序。 作業調度算法:採用基於先來先服務的調度算法。可以參考課本中的方法進行設計。 對於多道程序系統,要假定系統中具有的各種資源及數量、調度作業時必須考慮到每個作業的資源要求。 三、實驗主要儀器設備和材料 硬件環境:IBM-PC或兼容機 軟件環境:C語言編程環境 四、實驗原理及設計方案 採用多道程序設計方法的操作系統,在系統中要經常保留多個運行的作業,以提高系統效率。作業調度從系統已接納的暫存在輸入井中的一批作業中挑選出若干個可運行的作業,併為這些被選中的作業分配所需的系統資源。對被選中運行的作業必須按照它們各自的作業説明書規定的步驟進行控制。 採用先來先服務算法算法模擬設計作業調度程序。 (1)、作業調度程序負責從輸入井選擇若干個作業進入主存,為它們分配必要的資源,當它們能夠被進程調度選中時,就可佔用處理器運行。作業調度選擇一個作業的必要條件是系統中現有的尚未分配的資源可滿足該作業的資源要求。但有時系統中現有的尚未分配的資源既可滿足某個作業的要求也可滿足其它一些作業的'要求,那麼,作業調度必須按一定的算法在這些作業中作出選擇。先來先服務算法是按照作業進入輸入井的先後次序來挑選作業,先進入輸入井的作業優先被挑選,當系統中現有的尚未分配的資源不能滿足先進入輸入井的作業時,那麼順序挑選後面的作業。 (2) 假定某系統可供用户使用的主存空間共100k,並有5台磁帶機。 (3)流程圖: 五、結果過程及截圖 讀取文件來初始化主存,磁帶機的個數,並打印出來。 初始時間是9:00: 按Y運行5分鐘: 按Y運行5分鐘: 按Y運行5分鐘: 多次運行後最後狀態: 六、所遇困難的解決以及心得體會 這個實驗是花的時間最多的一個實驗,第一次做的時候由於理解有些問題,所以做錯了。之後重新做了一遍,收穫還是很多的,遇到了很多的細節問題,例如像是時間化成浮點數和浮點數化成時間等一些問題,從中也暴露了自己的編程能力欠缺,之後要多多的寫程序。 七、思考題 1、寫出每種算法的調度策略,最後比較各種算法的優缺點。 答:先來先服務算法是根據作業的進入時間來排序,到達時間短的先運行,優點是實現簡單,缺點是運行時間慢。 短作業優先算法是根椐作業的估計運行時間來排序,估計運行時間短的先運行,優點是運行時間快,缺點是實現起來比較複雜。 2、選擇調度算法的依據是什麼? 答:如果作業要求的速度不高,而且作業比較小型,那就最好用先來先服務算法。 如果作業要求的速度高,作業流程複雜,那就最好用短作業優先算法。 八、源代碼 #include #include #include #include #define getjcb() (JCB*)malloc(sizeof(JCB)) typedef struct {//資源的總量 int memory; int tape; }RESOURCE; typedef struct JCB {//作業控制塊 char username[20];//用户名 char jobname[10];//作業名 char state;//作業狀態 char atime[5];//到達時間 float rtime;//運行時間 RESOURCE resource;//資源數量 struct JCB*link; }JCB; RESOURCE source = {100,5}; JCB *pjcb =getjcb();//作業鏈表頭 char nowtime[5];//現在時間,初始時間為9:00 FILE* ignore(FILE *fp)//忽略文件中的空白符 { if(feof(fp)) return fp; char ch = fgetc(fp); while (!feof(fp) && (ch == || ch == )){ ch = fgetc(fp); } //if(!feof(fp)) return fp; fseek(fp, -1, SEEK_CUR); return fp; } FILE* findFILE *fp,char c)//在文件中找到一個字符的位置(讀取文件時用) { if(feof(fp)) return fp; char ch = fgetc(fp); while (!feof(fp) && (ch != c)){ } ch = fgetc(fp); fseek(fp, -1, SEEK_CUR); return fp; } void destory()//釋放鏈表所佔的內存 { JCB *p = pjcb->link; while(pjcb){ free(pjcb); pjcb = p; if(p) p = p->link; } } float stof(char *time)//把時間轉化為浮點型數 { float h = 0, m = 0; int i = 0; while(time[i] != :){ h = h*10 + time[i] - 0; } i++; while(time[i] != ){ m = m*10 + time[i] - 0; } i++; i++; return (h + m/60); } char* ftos(double ftime)//把浮點型數值轉化為時間 { } float timesub(char *time1, char *time2)//兩個時間相減,得到時間差 { } void print()//打印輸出 { JCB *p = pjcb->link; printf( p->atime, p->rtime, p->,p->); } void sendsource()//為作業分配資源 { JCB *p; p = pjcb->link; while(p){//為到達的作業調度 p = p->link; } if(p->state == W && - p->>=0 && - p-> >=0){ } } p = p->link; p->state = R; -= p->; -= p->; printf( } void init()//初始化,讀取文件中的作業信息 { FILE *fp; JCB *p= NULL,*q = pjcb ; if((fp = fopen( } } fp = ignore(fp); p->rtime = 0;//不初始化則會發生錯誤,????? fscanf(fp, int checkend() //檢查是否所有的作業都已經運行完了 { JCB *p = pjcb ->link; while(p){ if(p ->state != F){ return 0; } p = p->link; } return 1; } void run()//運行作業 { if(checkend()){//檢查是否所有的作業都已經運行完了 printf( } } p = p->link; } p = pjcb ->link; while(p){//計算到達的作業 if( strcmp(nowtime, p->atime) ==0 && p->state == N){ p->state = W; printf( int main() { char ch; double time =9.00; } double step = float(5)/60+0.00001; ftos(9.0); init(); do{ run(); puts(操作系統實驗報告 篇二
操作系統實驗報告 篇三