第一篇:操作系統(tǒng)實(shí)驗(yàn)報(bào)告
許昌學(xué)院
《操作系統(tǒng)》實(shí)驗(yàn)報(bào)告書(shū)
學(xué)號(hào):姓名:閆金科班級(jí):成績(jī):
5006140057
14物聯(lián)網(wǎng)工程 2016年02月實(shí)驗(yàn)一 Linux的安裝與配置
一、實(shí)驗(yàn)?zāi)康?/p>
1.熟悉Linux系統(tǒng)的基本概念,比如Linux發(fā)行版、宏內(nèi)核、微內(nèi)核等。2.掌握Linux系統(tǒng)的安裝和配置過(guò)程,初步掌握Linux系統(tǒng)的啟動(dòng)和退出方法。3.熟悉Linux系統(tǒng)的文件系統(tǒng)結(jié)構(gòu),了解Linux常用文件夾的作用。
二、實(shí)驗(yàn)內(nèi)容
1.從網(wǎng)絡(luò)上下載VMware軟件和兩個(gè)不同Linux發(fā)行版鏡像文件。2.安裝VMware虛擬機(jī)軟件。
3.在VMware中利用第一個(gè)鏡像文件完成第一個(gè)Linux的安裝,期間完成網(wǎng)絡(luò)信息、用戶信息、文件系統(tǒng)和硬盤(pán)分區(qū)等配置。
4.在VMware中利用第二個(gè)鏡像文件完成第二個(gè)Linux的安裝,并通過(guò)LILO或者GRUB解決兩個(gè)操作系統(tǒng)選擇啟動(dòng)的問(wèn)題。
5.啟動(dòng)Linux系統(tǒng),打開(kāi)文件瀏覽器查看Linux系統(tǒng)的文件結(jié)構(gòu),并列舉出Linux常用目錄的作用。
三、實(shí)驗(yàn)過(guò)程及結(jié)果
1、啟動(dòng)VMware,點(diǎn)擊新建Linux虛擬機(jī),如圖所示:
2、點(diǎn)擊下一步,選擇經(jīng)典型,點(diǎn)擊下一步在選擇客戶機(jī)頁(yè)面選擇Linux,版本選擇Red Hat Enterprise Linux 5,如圖所示:
3、點(diǎn)擊下一步創(chuàng)建虛擬機(jī)名稱以及所要安裝的位置,如圖所示:
4、點(diǎn)擊下一步,磁盤(pán)容量填一個(gè)合適大小,此處選擇默認(rèn)值大小10GB,如圖所示:
5、點(diǎn)擊完成,點(diǎn)擊編輯虛擬機(jī)設(shè)置,選擇硬件選項(xiàng)中的CD-ROM(IDE...)選項(xiàng),在右側(cè)連接中選擇“使用ISO鏡像(I)”選項(xiàng),點(diǎn)擊“瀏覽”,找到Linux的鏡像文件,如圖所示:
6點(diǎn)擊確定按鈕后,點(diǎn)擊啟動(dòng)虛擬機(jī)按鈕,來(lái)到Linux的安裝界面,如圖所示:
7、到此頁(yè)面之后,等待自動(dòng)檢測(cè)安裝,如圖所示:
8、等到出現(xiàn)如圖所示頁(yè)面后點(diǎn)擊“skip”按鈕,跳過(guò)檢測(cè),直接進(jìn)入安裝設(shè)置界面,如圖所示:
9、安裝設(shè)計(jì)界面如圖所示:
10、點(diǎn)擊Next按鈕進(jìn)入設(shè)置語(yǔ)言界面,設(shè)置語(yǔ)言為“簡(jiǎn)體中文”,如圖所示:
11、點(diǎn)擊Nest按鈕進(jìn)入系統(tǒng)鍵盤(pán)設(shè)置按鈕,設(shè)置系統(tǒng)鍵盤(pán)為“美國(guó)英語(yǔ)式”,如圖所示:
12、點(diǎn)擊下一步按鈕,彈出“安裝號(hào)碼”對(duì)話框,選擇跳過(guò)輸入安裝號(hào)碼,如圖所示:
13、按照提示,一直點(diǎn)擊下一步按鈕,如圖所示:
14、到設(shè)置最后一步,點(diǎn)擊下一步按鈕進(jìn)入開(kāi)始安裝Red Hat Enterprise Linux Sever界面,如圖所示:
15、安裝完成后,進(jìn)入歡迎界面,按照提示點(diǎn)擊前進(jìn)按鈕知道進(jìn)入Linux桌面,如圖所示:
16、安裝成功的Linux系統(tǒng)桌面如圖所示,桌面包含五個(gè)圖標(biāo),分別為:計(jì)算機(jī)、jk’s Home、回收站、RHEL/5.3 i386DVD。
四、實(shí)驗(yàn)總結(jié)
通過(guò)安裝虛擬機(jī)等操作讓我認(rèn)識(shí)到Linux這系統(tǒng)一些基本特點(diǎn),本次試驗(yàn)學(xué)會(huì)了安裝虛擬機(jī)并且使用虛擬機(jī)安裝操作系統(tǒng),掌握了紅帽Linux系統(tǒng)的安裝和配置過(guò)程,以及對(duì)鏡像ISO文件的使用,有別于我們機(jī)器上使用的系統(tǒng),通過(guò)虛擬機(jī)這個(gè)軟件還可以在已有系統(tǒng)的基礎(chǔ)上使用其他操作系統(tǒng)。安裝過(guò)程中一定要注意選擇版本的時(shí)候要選擇Red Hat Enterprise Linux 5版本,否則安裝不能成功。自己動(dòng)手成功的安裝了Linux系統(tǒng),自己對(duì)Linux的學(xué)習(xí)產(chǎn)生更大的興趣。
實(shí)驗(yàn)二 Linux操作系統(tǒng)的運(yùn)行模式
一、實(shí)驗(yàn)?zāi)康?/p>
1.熟悉Linux系統(tǒng)終端工作環(huán)境的使用,了解Linux命令的格式,使用學(xué)會(huì)利用常用的Linux命令來(lái)完成系統(tǒng)的管理和維護(hù)。
2.了解X-Windows的特點(diǎn),熟悉Linux圖形用戶接口的使用,掌握GNOME桌面環(huán)境的基本操作。
3.了解和掌握在Linux環(huán)境下安裝軟件包的方法,如QQ for Linux等用軟件的安裝方法。
二、實(shí)驗(yàn)內(nèi)容
1.啟動(dòng)Linux系統(tǒng)打開(kāi)虛擬終端界面,使用Linux的在線幫助指令man或help獲得ls、uname、date、cal、mkdir、cp等Linux命令的幫助手冊(cè),了解這些命令的具體使用方法。同時(shí),也可以通過(guò)執(zhí)行“命令名 –help”來(lái)顯示該命令的幫助信息,如“l(fā)s –help”,試用這些命令。
2.通過(guò)uname命令的執(zhí)行,查看并給出相關(guān)系統(tǒng)信息:操作系統(tǒng)的名稱、系統(tǒng)域名、系統(tǒng)CPU名稱等。
3.在主目錄下創(chuàng)建一個(gè)名為myetc的子目錄,將/etc目錄下與網(wǎng)絡(luò)相關(guān)的文件和子目錄拷貝到該目錄,并將這些文件的執(zhí)行權(quán)限設(shè)置為可執(zhí)行。
4.在主目錄/home下創(chuàng)建目錄program、music 和temp,然后在program下建立目錄java和C,列出完成該過(guò)程的所有命令。
5.在圖形界面環(huán)境中,查看GNOME桌面的面板和桌面,設(shè)置GNOME,包括屏幕保護(hù)程序、更改背景和指定關(guān)聯(lián)程序等。6.實(shí)現(xiàn)對(duì)光盤(pán)的加載和訪問(wèn),然后卸載。
三、實(shí)驗(yàn)過(guò)程及結(jié)果
1、打開(kāi)終端,輸入 【ls –help】來(lái)查看【ls】指令的使用方法,同理查看uname、date、cal、mkdir、cp的使用方法。
2、在終端中輸入【uname –a】顯示操作系統(tǒng)名系統(tǒng)cpu名和系統(tǒng)域名
3、重啟系統(tǒng),用【root】用戶名進(jìn)入系統(tǒng),以獲得權(quán)限。在終端中輸入【mkdir myetc】,在主目錄下創(chuàng)建【myrtc】的目錄,【ls】查看是否創(chuàng)建。輸入【cd..】返回至【/】文件,輸入【cp –r etc root/myetc】講etc中內(nèi)容復(fù)制到myetc中,進(jìn)入myetc文件【ls】查看。輸入
【chmod u+x etc】賦予文件可執(zhí)行的權(quán)限,輸入【ll】查看。
4、在home下,輸入【mkdir {program,music,temp}】,可在home下創(chuàng)立這三個(gè)目錄,輸入【ls】查看。在program下輸入【mkdir{java,C}】,可創(chuàng)立java和C兩個(gè)目錄,【ls】查看。
5、在桌面上方選擇【系統(tǒng)】-【首選項(xiàng)】,即可設(shè)置屏幕保護(hù)程序和更改背景和指定關(guān)聯(lián)程序
5、在桌面上可見(jiàn)看到有CD光盤(pán),雙擊瀏覽,右鍵【彈出】即卸載。
四、實(shí)驗(yàn)總結(jié)和體會(huì)
Linux的指令系統(tǒng)是學(xué)習(xí)Linux操作系統(tǒng)很重要的一部分,指令系統(tǒng)相當(dāng)于在Windows操作系統(tǒng)下的doc,可以省去圖形化界面。通過(guò)這次的實(shí)驗(yàn)讓我了解了Linux的強(qiáng)大功能,了解到Linux有許多方便快捷的設(shè)置基本配置的方法,這使我更喜歡上Linux的使用。在使用指令的過(guò)程中,有時(shí)候?qū)ξ募牟僮餍枰欢ǖ臋?quán)限,這時(shí)需要在登陸時(shí)用戶名使用【root】,而不是我們?cè)诎惭b時(shí)使用的用戶名,這樣就獲得了管理員權(quán)限,可以對(duì)一些系統(tǒng)文件進(jìn)行操作。
實(shí)驗(yàn)三 Linux應(yīng)用軟件與系統(tǒng)管理
一、實(shí)驗(yàn)?zāi)康?/p>
1.了解OpenOffice.Org集成辦公軟件,掌握利用OpenOffice.Org的套件來(lái)完成文檔和圖片的處理。
2.了解Linux網(wǎng)絡(luò)管理的知識(shí),熟悉Linux網(wǎng)絡(luò)配置的方法,掌握在Linux環(huán)境下配置Web服務(wù)器和ftp服務(wù)的方法。
二、實(shí)驗(yàn)內(nèi)容
1.配置Linux系統(tǒng)的網(wǎng)絡(luò)環(huán)境,安裝FTP和Web服務(wù)器,并配置相關(guān)的屬性,利用FTP實(shí)現(xiàn)WINDOWS和Linux之間的數(shù)據(jù)交換。
2.利用FTP程序上傳自己的照片到FTP服務(wù)器,利用OpenOffice的文字處理工具OpenOffice Writer制作一份表格形式的個(gè)人簡(jiǎn)歷。個(gè)人簡(jiǎn)歷中至少包含學(xué)號(hào)、姓名、性別、專業(yè)、照片和學(xué)習(xí)經(jīng)歷等內(nèi)容,并保存為網(wǎng)頁(yè)格式(html格式)。3.將個(gè)人簡(jiǎn)歷網(wǎng)頁(yè)設(shè)置為WEB服務(wù)器的首頁(yè),然后在客戶端利用瀏覽器訪問(wèn)WEB服務(wù)器,查看效果。
4.通過(guò)讀取proc文件系統(tǒng),獲取系統(tǒng)各種信息(如主機(jī)名、系統(tǒng)啟動(dòng)時(shí)間、運(yùn)行時(shí)間、版本號(hào)、所有進(jìn)程信息、CPU使用率等),并以比較容易的方式顯示。
三、實(shí)驗(yàn)過(guò)程及結(jié)果
1.配置網(wǎng)絡(luò)環(huán)境:在(服務(wù).cmd).里面進(jìn)行以下操作:在服務(wù)里選擇3按回車
完成后,可在本地連接看到VMware已連接上網(wǎng)絡(luò)
在虛擬機(jī)設(shè)置中設(shè)置以太網(wǎng)網(wǎng)絡(luò)連接方式為
網(wǎng)關(guān)地址填虛擬機(jī)的網(wǎng)管,IP地址設(shè)為虛擬機(jī)的一個(gè)子網(wǎng):
四、總結(jié):
在linux系統(tǒng)下,make是我們經(jīng)常用到的編譯命令,所以關(guān)于make代碼和他的操作指令一定要記清楚。所以,熟練掌握了make和makefile工具之后,源碼安裝軟件就變的像windows下安裝軟件一樣簡(jiǎn)單。
實(shí)驗(yàn)四 進(jìn)程控制與管理
一、實(shí)驗(yàn)?zāi)康?/p>
1.掌握GCC編譯器的用法,學(xué)會(huì)利用GCC編輯器來(lái)編輯C語(yǔ)言程序,學(xué)會(huì)利用GDB調(diào)試器來(lái)調(diào)試C語(yǔ)言程序。
2.理解進(jìn)程和程序的區(qū)別和聯(lián)系,3.掌握在Linux環(huán)境下觀察進(jìn)程運(yùn)行情況和CPU工作情況的命令。4.了解fork()系統(tǒng)調(diào)用,掌握利用fork()創(chuàng)建進(jìn)程的方法。
5.了解Linux系統(tǒng)其他與進(jìn)程相關(guān)的系統(tǒng)調(diào)用,如exec、wait和exit等。6.了解Linux常用的進(jìn)程通信機(jī)制。
二、實(shí)驗(yàn)內(nèi)容
1.利用Linux的進(jìn)程管理命令ps、top來(lái)監(jiān)視和跟蹤進(jìn)程,體會(huì)進(jìn)程和程序的關(guān)系。2.利用Linux的文字編輯器編寫(xiě)文件復(fù)制的C語(yǔ)言程序,并用gcc編譯該程序,然后運(yùn)行該程序。
3.編寫(xiě)一段程序,使用系統(tǒng)調(diào)用fork()創(chuàng)建兩個(gè)子進(jìn)程。當(dāng)此程序運(yùn)行時(shí),在系統(tǒng)中有一個(gè)父進(jìn)程和兩個(gè)子進(jìn)程活動(dòng)。讓每一個(gè)進(jìn)程在屏幕上顯示一個(gè)字符:父進(jìn)程顯示'a',子進(jìn)程分別顯示字符'b'和字符'c'。試觀察記錄屏幕上的顯示結(jié)果,并分析原因。
4.修改上述程序,每一個(gè)進(jìn)程循環(huán)顯示一句話。子進(jìn)程顯示'daughter ?'及'son ??',父進(jìn)程顯示 'parent ??',觀察結(jié)果,分析原因。5.用fork()創(chuàng)建一個(gè)進(jìn)程,再調(diào)用exec()用新的程序替換該子進(jìn)程的內(nèi)容。
三、實(shí)驗(yàn)過(guò)程及結(jié)果
1、利用Linux的進(jìn)程管理命令ps、top來(lái)監(jiān)視和跟蹤進(jìn)程,體會(huì)進(jìn)程和程序的關(guān)系。<1>從用戶身份切換到ROOT身份
<2>輸入命令 ps 查看進(jìn)程
<2>輸入命令 top 跟蹤進(jìn)程
2、利用Linux的文字編輯器編寫(xiě)一個(gè)計(jì)算機(jī)100個(gè)自然數(shù)和的C語(yǔ)言程序,并用gcc編譯該程序,然后運(yùn)行該程序。
<1>創(chuàng)建一個(gè).C文件 并進(jìn)入進(jìn)行編輯
<2>用GCC 進(jìn)行編譯,再查看文件,發(fā)現(xiàn)產(chǎn)生執(zhí)行文件 a.out
<3>執(zhí)行這個(gè)可執(zhí)行文件得到結(jié)果5050
1、編寫(xiě)一段程序,使用系統(tǒng)調(diào)用fork()創(chuàng)建兩個(gè)子進(jìn)程。當(dāng)此程序運(yùn)行時(shí),在系統(tǒng)中有一個(gè)父進(jìn)程和兩個(gè)子進(jìn)程活動(dòng)。讓每一個(gè)進(jìn)程在屏幕上顯示一個(gè)字符:父進(jìn)程顯示'a',子進(jìn)程分別顯示字符'b'和字符'c'。試觀察記錄屏幕上的顯示結(jié)果,并分析原因。
<1>穿件一個(gè).C文件 并進(jìn)行編寫(xiě)程序代碼
<2>反復(fù)執(zhí)行2次該程序
<3>可以看出兩次執(zhí)行的結(jié)果 a b c 出現(xiàn)的順序不同,原因是,3個(gè)進(jìn)程的輸出次序是隨機(jī)的,并不會(huì)按規(guī)定的順序出現(xiàn),所以會(huì)出現(xiàn)上述結(jié)果。
4、修改上述程序,每一個(gè)進(jìn)程循環(huán)顯示一句話。子進(jìn)程顯示'daughter ?'及'son ??',父進(jìn)程顯示 'parent ??',觀察結(jié)果,分析原因。<1>重新修改代碼
<3>執(zhí)行這段程序
<4>原分析:
因和之前一樣,可以看出執(zhí)行的結(jié)果 3個(gè)單詞出現(xiàn)的順序不同,原因是,3個(gè)進(jìn)程的輸出次序是隨機(jī)的,并不會(huì)按規(guī)定的順序出現(xiàn),所以會(huì)出現(xiàn)上述結(jié)果。
5、用fork()創(chuàng)建一個(gè)進(jìn)程,再調(diào)用exec()用新的程序替換該子進(jìn)程的內(nèi)容。<1>
編寫(xiě)代碼
<2> 執(zhí)行的結(jié)果
結(jié)果表明 execl 替代了son的內(nèi)容
四、實(shí)驗(yàn)總結(jié)和體會(huì)
這個(gè)實(shí)驗(yàn)考察的是進(jìn)程之間存在很多可能性以及對(duì)編輯器的使用。本次實(shí)驗(yàn)學(xué)習(xí)了在linux環(huán)境下用gcc編譯器運(yùn)行c語(yǔ)言程序,在linux環(huán)境下編寫(xiě)程序用到了vi編輯器,知道了該編輯器也需要各種命令來(lái)操作。編寫(xiě)C語(yǔ)言程序時(shí)用到了fork()函數(shù),再調(diào)用execl()用新的程序替換該子進(jìn)程的內(nèi)容。
實(shí)驗(yàn)五 進(jìn)程調(diào)度模擬程序的設(shè)計(jì)與實(shí)現(xiàn)
一、實(shí)驗(yàn)?zāi)康?/p>
1.了解進(jìn)程調(diào)度的概念,掌握常用進(jìn)程調(diào)度算法的原理。2.掌握Linux程序設(shè)計(jì)編輯、編譯和調(diào)試的技巧。
二、實(shí)驗(yàn)內(nèi)容
1.編寫(xiě)程序?qū)崿F(xiàn)進(jìn)程調(diào)度調(diào)度算法先來(lái)先服務(wù)、優(yōu)先級(jí)高優(yōu)先和時(shí)間片輪轉(zhuǎn)調(diào)度算法。(編程語(yǔ)言不限)
2.輸入數(shù)據(jù),輸出運(yùn)行結(jié)果。
三、實(shí)驗(yàn)過(guò)程及結(jié)果
1先來(lái)先服務(wù)
#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;} /*判斷有沒(méi)有進(jìn)程在前個(gè)進(jìn)程完成前到達(dá)*/ } if(b!=0)/*有進(jìn)程到達(dá)則按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)/*定義執(zhí)行進(jìn)程后相關(guān)數(shù)據(jù)的修改*/ { int i,g=0;for(i=0;i<4;i++){ if(arrayTask[i].Status==0)continue;else { g=1;break;} } if(g==0)/*當(dāng)處理的是第一個(gè)未執(zhí)行的進(jìn)程時(shí)執(zhí)行*/ { 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)/*當(dāng)處理的不是第一個(gè)未執(zhí)行的進(jìn)程時(shí)執(zhí)行*/ { 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++)/*查找最后執(zhí)行的進(jìn)程的完成時(shí)間*/ { 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)/*定義打印函數(shù)*/ { 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++)/*調(diào)用兩個(gè)函數(shù)改變結(jié)構(gòu)體數(shù)的值*/ { k=fcfs();d[b]=k;new(k);} for(b=0;b<4;b++) Printresult(d[b]);/*調(diào)用打印函數(shù)打出結(jié)果*/ 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”);} } } 四、實(shí)驗(yàn)總結(jié)和體會(huì) 通過(guò)做本實(shí)驗(yàn),讓我對(duì)進(jìn)程或作業(yè)先來(lái)先服務(wù)、高優(yōu)先權(quán)、按時(shí)間片輪轉(zhuǎn)調(diào)度算法以及進(jìn)程調(diào)度的概念和算法,有了更深入的認(rèn)識(shí)!理解進(jìn)程的狀態(tài)及變化,動(dòng)態(tài)顯示每個(gè)進(jìn)程的當(dāng)前狀態(tài)及進(jìn)程的調(diào)度情況。進(jìn)程調(diào)度是處理機(jī)管理的核心內(nèi)容。優(yōu)先級(jí)高優(yōu)先是根據(jù)作業(yè)的優(yōu)先級(jí),總是選擇優(yōu)先級(jí)最高者進(jìn)入隊(duì)列。輪轉(zhuǎn)調(diào)度算法是調(diào)度程序每次把CPU分配給就緒隊(duì)列首進(jìn)程/線程使用規(guī)定的時(shí)間間隔,就緒隊(duì)列中都路保留巡行一個(gè)時(shí)間片。 實(shí)驗(yàn)二 進(jìn)程調(diào)度 1.目的和要求 通過(guò)這次實(shí)驗(yàn),理解進(jìn)程調(diào)度的過(guò)程,進(jìn)一步掌握進(jìn)程狀態(tài)的轉(zhuǎn)變、進(jìn)程調(diào)度的策略,進(jìn)一步體會(huì)多道程序并發(fā)執(zhí)行的特點(diǎn),并分析具體的調(diào)度算法的特點(diǎn),掌握對(duì)系統(tǒng)性能的評(píng)價(jià)方法。 2.實(shí)驗(yàn)內(nèi)容 閱讀教材《計(jì)算機(jī)操作系統(tǒng)》第二章和第三章,掌握進(jìn)程管理及調(diào)度相關(guān)概念和原理。 編寫(xiě)程序模擬實(shí)現(xiàn)進(jìn)程的輪轉(zhuǎn)法調(diào)度過(guò)程,模擬程序只對(duì)PCB進(jìn)行相應(yīng)的調(diào)度模擬操作,不需要實(shí)際程序。假設(shè)初始狀態(tài)為:有n個(gè)進(jìn)程處于就緒狀態(tài),有m個(gè)進(jìn)程處于阻塞狀態(tài)。采用輪轉(zhuǎn)法進(jìn)程調(diào)度算法進(jìn)行調(diào)度(調(diào)度過(guò)程中,假設(shè)處于執(zhí)行狀態(tài)的進(jìn)程不會(huì)阻塞),且每過(guò)t個(gè)時(shí)間片系統(tǒng)釋放資源,喚醒處于阻塞隊(duì)列隊(duì)首的進(jìn)程。 程序要求如下: 1)輸出系統(tǒng)中進(jìn)程的調(diào)度次序; 2)計(jì)算CPU利用率。 3.實(shí)驗(yàn)環(huán)境 Windows操作系統(tǒng)、VC++6.0 C語(yǔ)言 4設(shè)計(jì)思想: (1) 程序中進(jìn)程可用PCB表示,其類型描述如下: struct PCB_type { int pid; //進(jìn)程名 int state; //進(jìn)程狀態(tài) 2——表示“執(zhí)行”狀態(tài) 1——表示“就緒”狀態(tài) 0——表示“阻塞”狀態(tài) int cpu_time;//運(yùn)行需要的CPU時(shí)間(需運(yùn)行的時(shí)間片個(gè)數(shù)) } 用PCB來(lái)模擬進(jìn)程; (2)設(shè)置兩個(gè)隊(duì)列,將處于“就緒”狀態(tài)的進(jìn)程PCB掛在隊(duì)列ready中;將處于“阻塞”狀態(tài)的進(jìn)程PCB掛在隊(duì)列blocked中。隊(duì)列類型描述如下: struct QueueNode{ struct PCB_type PCB; Struct QueueNode *next;} 并設(shè)全程量: struct QueueNode *ready_head=NULL,//ready隊(duì)列隊(duì)首指針 *ready_tail=NULL , //ready隊(duì)列隊(duì)尾指針 *blocked_head=NULL,//blocked隊(duì)列隊(duì)首指針 *blocked_tail=NULL;//blocked隊(duì)列隊(duì)尾指針(3)設(shè)計(jì)子程序: start_state(); 讀入假設(shè)的數(shù)據(jù),設(shè)置系統(tǒng)初始狀態(tài),即初始化就緒隊(duì)列和阻塞隊(duì)列。 dispath(); 模擬調(diào)度,當(dāng)就緒隊(duì)列的隊(duì)首進(jìn)程運(yùn)行一個(gè)時(shí)間片后,放到就緒隊(duì)列末尾,每次都是隊(duì)首進(jìn)程進(jìn)行調(diào)度,一個(gè)進(jìn)程運(yùn)行結(jié)束就從就緒隊(duì)列中刪除,當(dāng)?shù)絫個(gè)時(shí)間片后,喚醒阻塞隊(duì)列隊(duì)首進(jìn)程。 calculate(); 就緒進(jìn)程運(yùn)行一次,usecpu加1,當(dāng)就緒隊(duì)列為空時(shí)unusecpu加1,CPU利用率為use_cpu/(use_cpu+unuse_cpu)。 5源代碼: #include struct PCB_type { int pid; //進(jìn)程名 int state; //進(jìn)程狀態(tài) //2--表示“執(zhí)行”狀態(tài) //1--表示“就緒”狀態(tài) //0--表示“阻塞”狀態(tài) int cpu_time;//運(yùn)行需要的CPU時(shí)間(需運(yùn)行的時(shí)間片個(gè)數(shù))};struct QueueNode{ struct PCB_type PCB; struct QueueNode *next;};struct QueueNode *ready_head=NULL,//ready隊(duì)列隊(duì)首指針 *ready_tail=NULL,//ready隊(duì)列隊(duì)尾指針 *block_head=NULL,//blocked隊(duì)列隊(duì)首指針 *block_tail=NULL; //blocked隊(duì)列隊(duì)尾指針 int use_cpu,unuse_cpu; void start_state()//讀入假設(shè)的數(shù)據(jù),設(shè)置系統(tǒng)初始狀態(tài) { int n,m; int i; struct QueueNode *p,*q; printf(“輸入就緒節(jié)點(diǎn)個(gè)數(shù)n:”); scanf(“%d”,&n); printf(“輸入阻塞節(jié)點(diǎn)個(gè)數(shù)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(“輸入就緒進(jìn)程%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(“輸入阻塞進(jìn)程%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處于就緒狀態(tài)的進(jìn)程有:n”); p=ready_head->next; i=1; while(p) {printf(“進(jìn)程%d的pid和cpu_time:%5d%5d%5dn“,i,p->PCB.pid,p->PCB.state,p->PCB.cpu_time); p=p->next; i++; } } void dispath() //模擬調(diào)度 { int x=0,t; use_cpu=0; unuse_cpu=0; printf(”輸入t:“); scanf(”%d“,&t); printf(”開(kāi)始調(diào)度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(”進(jìn)程%d調(diào)度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(”進(jìn)程%d完成t“,p->PCB.pid); free(p); } } else { unuse_cpu++; x++; printf(”空閑一個(gè)時(shí)間片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() //計(jì)算CPU利用率 { printf(”ncpu的利用率%.2fn“,(float)use_cpu/(use_cpu+unuse_cpu)); } void main(){start_state(); dispath(); calculate();} 6運(yùn)行結(jié)果: 7實(shí)驗(yàn)總結(jié): 實(shí)驗(yàn)幫我復(fù)習(xí)了數(shù)據(jù)結(jié)構(gòu)和C語(yǔ)言,且鞏固課本知識(shí),知道了如何定義結(jié)構(gòu)體,如何在鏈接隊(duì)列中增刪節(jié)點(diǎn)。模擬進(jìn)程調(diào)度幫我們鞏固了進(jìn)程三狀態(tài)之間的變遷。懂得調(diào)式的重要性??傊?,我們明白了理論聯(lián)系實(shí)際。多看書(shū),多上機(jī)。 實(shí)驗(yàn)三 可變分區(qū)存儲(chǔ)管理 1.目的和要求 通過(guò)這次實(shí)驗(yàn),加深對(duì)內(nèi)存管理的認(rèn)識(shí),進(jìn)一步掌握內(nèi)存的分配、回收算法的思想。 2.實(shí)驗(yàn)內(nèi)容 閱讀教材《計(jì)算機(jī)操作系統(tǒng)》第四章,掌握存儲(chǔ)器管理相關(guān)概念和原理。編寫(xiě)程序模擬實(shí)現(xiàn)內(nèi)存的動(dòng)態(tài)分區(qū)法存儲(chǔ)管理。內(nèi)存空閑區(qū)使用自由鏈管理,采用最壞適應(yīng)算法從自由鏈中尋找空閑區(qū)進(jìn)行分配,內(nèi)存回收時(shí)假定不做與相鄰空閑區(qū)的合并。 假定系統(tǒng)的內(nèi)存共640K,初始狀態(tài)為操作系統(tǒng)本身占用64K。在t1時(shí)間之后,有作業(yè)A、B、C、D分別請(qǐng)求8K、16K、64K、124K的內(nèi)存空間;在t2時(shí)間之后,作業(yè)C完成;在t3時(shí)間之后,作業(yè)E請(qǐng)求50K的內(nèi)存空間;在t4時(shí)間之后,作業(yè)D完成。要求編程序分別輸出t1、t2、t3、t4時(shí)刻內(nèi)存的空閑區(qū)的狀態(tài)。 3.實(shí)驗(yàn)環(huán)境 Windows操作系統(tǒng)、VC++6.0 C語(yǔ)言 4.設(shè)計(jì)思想 模擬內(nèi)存分配和回收,要設(shè)置兩個(gè)鏈隊(duì)列,一個(gè)空閑區(qū)鏈和一個(gè)占用區(qū)鏈,空閑區(qū)鏈節(jié)點(diǎn)有起始地址,大小和指向下一節(jié)點(diǎn)的指針等數(shù)據(jù)域,占用區(qū)鏈節(jié)點(diǎn)有起始地址,大小,作業(yè)名和指向下一節(jié)點(diǎn)的指針等數(shù)據(jù)域,本實(shí)驗(yàn)用最壞適應(yīng)算法,每次作業(yè)申請(qǐng)內(nèi)存都是從空閑鏈隊(duì)頭節(jié)點(diǎn)分配,如果相等,就刪除空閑頭結(jié)點(diǎn),如果小于申請(qǐng)的,就不分配,否則就劃分內(nèi)存給作業(yè),剩下的內(nèi)存大小,重新插入空閑鏈隊(duì),按從大到小,接著把作業(yè)占用的內(nèi)存放到占用區(qū)鏈節(jié)點(diǎn)的末尾。每次作業(yè)運(yùn)行完,就要回收其占用的內(nèi)存大小,把作業(yè)節(jié)點(diǎn)按從大到小插入到空閑鏈隊(duì)中。5.源代碼: #include struct freelinkNode *next;};struct busylinkNode{ char name; int len;int address;struct busylinkNode *next;};struct freelinkNode *free_head=NULL; //自由鏈隊(duì)列(帶頭結(jié)點(diǎn))隊(duì)首指針 struct busylinkNode *busy_head=NULL; //占用區(qū)隊(duì)列隊(duì)(帶頭結(jié)點(diǎn))首指針 struct busylinkNode *busy_tail=NULL; //占用區(qū)隊(duì)列隊(duì)尾指針 void start(void)/* 設(shè)置系統(tǒng)初始狀態(tài)*/ { struct freelinkNode *p; struct busylinkNode *q; free_head=(struct freelinkNode*)malloc(sizeof(struct freelinkNode)); free_head->next=NULL;// 創(chuàng)建自由鏈頭結(jié)點(diǎn) busy_head=busy_tail=(struct busylinkNode*)malloc(sizeof(struct busylinkNode)); busy_head->next=NULL;// 創(chuàng)建占用鏈頭結(jié)點(diǎn) 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表示操作系統(tǒng)占用 */ q->len=64;q->address=0;q->next=NULL; busy_head->next=q;busy_tail=q;} void requireMemo(char name, int require)/*模擬內(nèi)存分配*/ { 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)/* 模擬內(nèi)存回收*/ { 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)/* 模擬系統(tǒng)過(guò)了time 時(shí)間*/ { printf(”過(guò)了時(shí)間%d后:n“,time);} void printlink()/* 輸出內(nèi)存空閑情況(自由鏈的結(jié)點(diǎn))*/ { freelinkNode *p; printf(”內(nèi)存的空閑情況為:n“); p=(struct freelinkNode *)malloc(sizeof(struct freelinkNode)); p=free_head->next; while(p!=NULL) { printf(”內(nèi)存的起始地址和內(nèi)存的大小%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.運(yùn)行結(jié)果: 7.實(shí)驗(yàn)總結(jié): 鞏固編程能力,和調(diào)式能力,復(fù)習(xí)課本知識(shí),明白理論聯(lián)系實(shí)際的重要性,動(dòng)手能力非常重要,多看書(shū),多獨(dú)立思考,品味痛苦的過(guò)程,享受成功的喜悅。 操作系統(tǒng)實(shí)驗(yàn)報(bào)告 院系:數(shù)計(jì)學(xué)院 班級(jí):大類6班 學(xué)號(hào):100511624 姓名:明章輝 指導(dǎo)教師:徐軍利 操作 系統(tǒng) 實(shí)驗(yàn)報(bào)告 實(shí)驗(yàn)名稱: 線程 控制實(shí)驗(yàn) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 目錄 一、實(shí)驗(yàn)?zāi)康暮鸵?2 二、實(shí)驗(yàn)內(nèi)容 2 三、實(shí)驗(yàn)步驟 2 四、實(shí)驗(yàn)結(jié)果與分析 3 1.單線程 3 2.單線程(睡眠 4s)3 3.多線程 4 4.多線程(每個(gè)子線程睡眠 1s)4 5.單線程與多線程對(duì)比 5 五、程序源代碼 5 1.單線程實(shí)驗(yàn)代碼 5 2.單線程實(shí)驗(yàn)代碼 6 六、實(shí)驗(yàn)體會(huì) 7 一、實(shí)驗(yàn)?zāi)康暮鸵?/p> 通過(guò)本實(shí)驗(yàn)掌握在 Linux 操作系統(tǒng)中遵循 Posix線程標(biāo)準(zhǔn)接口進(jìn)行多線程程序編程,熟練掌握線程的創(chuàng)建 pthread_create(),線程的終止 pthread_exit(),等待線程合并 pthread_join()等線程控制操作,利用信號(hào)量或者互斥鎖實(shí)現(xiàn)線程建的同步。 二、實(shí)驗(yàn)內(nèi)容 問(wèn)題:求 1000000 個(gè)浮點(diǎn)數(shù)(精確到小數(shù)點(diǎn)后 4 位)的平均值(和,最大值,最小值),具體的問(wèn)題描述流程圖如下圖圖 1 所示: 三、實(shí)驗(yàn) 步驟 1、隨機(jī)生成 1000000個(gè)浮點(diǎn)數(shù); 2、創(chuàng)建 4個(gè)子線程,分別求 250000個(gè)浮點(diǎn)數(shù)之和; 3、完成 1000000 個(gè)浮點(diǎn)數(shù)之和并打印結(jié)果; 4、統(tǒng)計(jì)多線程并發(fā)執(zhí)行完成計(jì)算的時(shí)間; 5、寫(xiě)一個(gè)單線程程序,同樣完成 1000000 個(gè)隨機(jī)數(shù)求和的計(jì)算,統(tǒng)計(jì)計(jì)算時(shí)間,并和前面結(jié)果進(jìn)行對(duì)比; 6、讓單線程程序睡眠四秒鐘、多線程程序各子程序睡一秒的條件下(兩個(gè)程序總的睡眠時(shí)間相同),對(duì)比執(zhí)行結(jié)果; 7、分析兩次對(duì)比結(jié)果的差異,寫(xiě)出自己的見(jiàn)解。 四、實(shí)驗(yàn)結(jié)果與分析 1、單線程完成 1000000 個(gè)浮點(diǎn)數(shù)的求和運(yùn)算所用的時(shí)間情況如下圖圖 2 所示: 圖 圖 2 單線程計(jì)算 時(shí)間 分析:實(shí)驗(yàn)中每次隨機(jī)產(chǎn)生一個(gè) 0 到 1 之間的浮點(diǎn)數(shù),1000000 個(gè)這樣的數(shù)相加的話的平總和大概就在 500000 左右(按照隨機(jī)數(shù)的平均值原理),實(shí)驗(yàn)中 sum=,顯然結(jié)果正確,整個(gè)計(jì)算運(yùn)行時(shí)間為。 2、單線程完成 1000000 個(gè)浮點(diǎn)數(shù)的求和運(yùn)算,單線程中睡眠 4 秒鐘,所用的時(shí)間情況如下圖圖3 所示: 圖 圖 3 單線程計(jì)算 時(shí)間(睡眠 4 秒)分析:根據(jù)上一次單線程的執(zhí)行情況來(lái)看,這一次讓單線程睡眠 4 秒鐘,最后執(zhí)行時(shí)間剛好就是4 秒加上計(jì)算時(shí)間。也就是說(shuō)計(jì)算 1000000 個(gè)浮點(diǎn)數(shù)的總和平均時(shí)間約為。 3、四個(gè)子線程共同完成 1000000 個(gè)浮點(diǎn)數(shù)的求和計(jì)算所用時(shí)間情況如下圖圖 4所示: 圖 圖 4 多線程計(jì)算時(shí)間 分析:因?yàn)檫@次是 4 個(gè)子線程并發(fā)運(yùn)行,每個(gè)子線程只需計(jì)算 250000個(gè)浮點(diǎn)數(shù)的總和,理想情況下這時(shí)候的運(yùn)行時(shí)間應(yīng)該是這單線程中計(jì)算時(shí)間的四分之一。從圖中可以看到執(zhí)行時(shí)間是,很顯然這個(gè)時(shí)間約為單線程求 1000000 個(gè)浮點(diǎn)數(shù)之和的時(shí)間()的四分之一,符合預(yù)期的結(jié)果。 4、四個(gè)子線程共同完成 1000000 個(gè)浮點(diǎn)數(shù)的求和計(jì)算,其中每個(gè)子線程睡眠 1 秒鐘,最終所用時(shí)間情況如下圖圖 5所示: 圖 圖 5 多線程計(jì)算時(shí)間(每個(gè) 子線程眠 睡眠 1 秒) 分析:這里四個(gè)子線程每個(gè)子線程睡眠一秒,但由于四個(gè)子線程并發(fā)同步的在執(zhí)行,當(dāng)一個(gè)子線程在睡眠時(shí),另外一個(gè)子線程卻仍然在繼續(xù)求和計(jì)算,因此他們一起合作同步完成1000000個(gè)浮點(diǎn)數(shù)的計(jì)算所需的時(shí)間就是 1 秒加上上圖中不睡眠的時(shí)候的計(jì)算時(shí)間。從圖中可以 看到≈1s+,所以最終的結(jié)果符合預(yù)期值。 5、單線程計(jì)算時(shí)間(睡眠 4s)與多線程計(jì)算時(shí)間(每個(gè)子線程睡眠 1s)對(duì)比效果如下圖圖 6 所示: 圖 圖 6 單線程(睡眠 4s)與 與 多線程(每個(gè)眠 子線程睡眠 1s)計(jì)算時(shí)間 對(duì)比圖 五、程序源代碼 /************************* *FileName: *Author: *Date:2013/11/22 ***************************/ #include <> #include <> #include <> #include <> #include int i; srand(time(NULL)); for(i=0;i { SUM +=(float)(rand()/(float)RAND_MAX); } sleep(4);} int main(){ pthread_t p; int result; float time; struct timeval start; struct timeval end; gettimeofday(&start,NULL); result=pthread_create(&p,NULL,ADD,NULL); if(result!=0) { printf(“Create Thread of ADD Failuren”); exit(-1); } pthread_join(p,NULL); gettimeofday(&end,NULL); time =((float)-*1000000+(float) -)/1000000; printf(“Signal_Thread_Sum:%.4fn”,SUM); printf(“Signal_Thread_Execution_Time:%.4fs(sleep 4 sec)n”,time); return 0;} /************************* *FileName: *Author:wangtao *Date:2013/11/22 ***************************/ #include <> #include <> #include <> #include <> #include int i; srand(time(NULL)); for(i=0;i { pthread_mutex_lock(&mutex); SUM +=(float)((float)rand()/RAND_MAX); pthread_mutex_unlock(&mutex); } printf(“pthread%d:%.4fn”,*k,SUM); sleep(1);} int main(void){ pthread_t p1,p2,p3,p4; int result1,result2,result3,result4; int k1=1,k2=2,k3=3,k4=4; struct timeval start; struct timeval end; float time; gettimeofday(&start,NULL); pthread_mutex_init(&mutex,NULL); result1=pthread_create(&p1,NULL,(void*)ADD,&k1); result2=pthread_create(&p2,NULL,(void*)ADD,&k2); result3=pthread_create(&p3,NULL,(void*)ADD,&k3); result4=pthread_create(&p4,NULL,(void*)ADD,&k4); if(result1!=0||result2!=0||result3!=0||result4!=0) { printf(“Create Child Thread Failure!n”); exit(1); } pthread_join(p1,NULL); pthread_join(p2,NULL); pthread_join(p3,NULL); pthread_join(p4,NULL); gettimeofday(&end,NULL); time =((float)-*1000000 +(float)-)/1000000; printf(“SUM = %.4fn”,SUM); printf(“Multi_thread_time = %.4fs(Each child thread sleep 1 sec)n”,time); return 0;} 六、實(shí)驗(yàn)體會(huì) 這是第一次使用多線程編程編寫(xiě)代碼,第一次直觀感受到這種多線程編程對(duì)程序的執(zhí)行速率的影響。雖然說(shuō)操作系統(tǒng)課程已經(jīng)上了好幾個(gè)星期了,課堂上一直在學(xué)習(xí)多線程編程的算法思想,但是那只是書(shū)面上的講授,真正直觀的感受和體會(huì)還是得依靠實(shí)驗(yàn)來(lái)了解。 因?yàn)橹熬徒佑|過(guò) linux 系統(tǒng),所以對(duì)于程序的編譯執(zhí)行方面還是問(wèn)題不大,最主要的就是代碼的編寫(xiě)問(wèn)題。一開(kāi)始到實(shí)驗(yàn)室完全不知道要做什么,因?yàn)楦具B實(shí)驗(yàn)內(nèi)容都不知道,直到助教在大屏幕上顯示這個(gè)實(shí)驗(yàn)題目,我才開(kāi)始了解實(shí)驗(yàn)的題目和要求。這里我就是想建議一下老師您可以應(yīng)該給我們實(shí)驗(yàn)題目,讓我們?cè)趯?shí)驗(yàn)前就了解一下實(shí)驗(yàn)內(nèi)容,不然到了實(shí)驗(yàn)室都不知道到底要干嘛。讀懂了解題意之后,我就開(kāi)始參考所給的一些線程創(chuàng)建函數(shù)說(shuō)明來(lái)編寫(xiě)多線程同步完成1000000個(gè)浮點(diǎn)數(shù)的求和運(yùn)算。因?yàn)閷?duì)這些線程函數(shù)不是很了解,在使用 pthread_create()函數(shù)創(chuàng)建線程時(shí),老是傳入函數(shù)參數(shù)不對(duì),后來(lái)百度之后了解到傳入的子線程函數(shù)的類型應(yīng)該為 void *(*start_thread)(void)形式。最后運(yùn)行試驗(yàn)與單線程的進(jìn)行比較,強(qiáng)烈感受到多線程的并發(fā)同步運(yùn)行的特點(diǎn)。 總之,這次試驗(yàn)使我對(duì)課堂知識(shí)有了更深的體會(huì)和鞏固,為以后的課程學(xué)習(xí)打下了基礎(chǔ)。 實(shí)驗(yàn)一 嵌入式開(kāi)發(fā)環(huán)境的建立 一、實(shí)驗(yàn)?zāi)康?/p> 通過(guò)此實(shí)驗(yàn)系統(tǒng),讀者可以了解嵌入式實(shí)時(shí)操作系統(tǒng) uC/OS-II 的內(nèi)核機(jī)制和運(yùn)行原理。本實(shí)驗(yàn)系統(tǒng)展示了 uC/OS-II 各方面的管理功能,包括信號(hào)量、隊(duì)列、內(nèi)存、時(shí)鐘等。在各個(gè)實(shí)驗(yàn)中具體介紹了 uC/OS-II 的相關(guān)函數(shù)。讀者在做實(shí)驗(yàn)的同時(shí)能夠結(jié)合理論知識(shí)加以分析,了解各個(gè)函數(shù)的作用和嵌入式應(yīng)用程序的設(shè)計(jì)方法,最終對(duì)整個(gè) uC/OS-II 和嵌入式操作系統(tǒng)的應(yīng)用有較為清楚的認(rèn)識(shí)。 二、實(shí)驗(yàn)步驟 1.安裝集成開(kāi)發(fā)環(huán)境LambdaEDU 集成開(kāi)發(fā)環(huán)境LambdaEDU 的安裝文件夾為 LambdaEDU,其中有一個(gè)名為“Setup.exe” 的文件,直接雙擊該文件便可啟動(dòng)安裝過(guò)程。具體的安裝指導(dǎo)請(qǐng)看“LambdaEDU 安裝手 冊(cè).doc”文件。 當(dāng) LambdaEDU 安裝完畢之后,我們看到的是一個(gè)空的界面,現(xiàn)在就開(kāi)始一步一步地將 我們的實(shí)驗(yàn)項(xiàng)目建立并運(yùn)行起來(lái)。 2.建立項(xiàng)目 為了我們的實(shí)驗(yàn)運(yùn)行起來(lái),需要建立1 個(gè)項(xiàng)目基于x86 虛擬機(jī)的標(biāo)準(zhǔn)應(yīng)用項(xiàng)目。通過(guò)點(diǎn) 擊“文件”、“新建”、“項(xiàng)目”開(kāi)始根據(jù)向?qū)?chuàng)建一個(gè)項(xiàng)目。 在隨后出現(xiàn)的對(duì)話框中選擇“Tool/標(biāo)準(zhǔn)應(yīng)用項(xiàng)目”,點(diǎn)擊下一步,開(kāi)始創(chuàng)建一個(gè)標(biāo)準(zhǔn)的 可執(zhí)行的應(yīng)用程序項(xiàng)目。 在隨后出現(xiàn)的對(duì)話框中填入項(xiàng)目名稱“ucos_x86_demo”。點(diǎn)擊“下一步”。 選擇“pc386 uC/OS-II 應(yīng)用(x86)”作為該項(xiàng)目的應(yīng)用框架。點(diǎn)擊“下一步” 選擇“pc386_elf_tra_debug”作為該項(xiàng)目的基本配置。點(diǎn)擊“完成”。 新創(chuàng)建的項(xiàng)目“ucos_x86_demo”將會(huì)被添加到項(xiàng)目列表。src 文件夾下保存了該項(xiàng)目中 包含的源文件。ucos2 文件夾中包含了移植到x86 虛擬機(jī)的全部代碼。init.c 文件是基于ucos2 和本虛擬機(jī)的一個(gè)應(yīng)用程序。在進(jìn)行ucos2 內(nèi)核實(shí)驗(yàn)中,只需要替換init.c 文件,即可。文 件名不限,但是文件名中最好不要使用英文符號(hào)和數(shù)字以外的其他字符,3.構(gòu)建項(xiàng)目 到這里,項(xiàng)目配置全部完成。接下來(lái)就可以進(jìn)行構(gòu)建項(xiàng)目了。 第一次構(gòu)建本項(xiàng)目,在此項(xiàng)目上點(diǎn)擊右鍵,選擇“重建BSP 及項(xiàng)目”。即可開(kāi)始構(gòu)建。 之后彈出的對(duì)話框顯示了構(gòu)建的進(jìn)度??梢渣c(diǎn)擊“在后臺(tái)運(yùn)行”,以隱藏該對(duì)話框 在構(gòu)建的同時(shí),在右下角的“構(gòu)建信息”視圖輸出構(gòu)建過(guò)程中的詳細(xì)信息: 注:“重新構(gòu)建”將本項(xiàng)目中的全部源代碼進(jìn)行一次完全的編譯和連接,花費(fèi)時(shí)間較多?!皹?gòu)建項(xiàng)目”則僅僅將新修改過(guò)的源代碼進(jìn)行編譯和連接,花費(fèi)時(shí)間最少?!爸亟˙SP及項(xiàng) 目”,不但要完成“重新構(gòu)建”的全部工作,另外還要編譯與該項(xiàng)目有關(guān)的的LambdaEDU 中內(nèi)置的部分代碼,花費(fèi)時(shí)間最多。但是在項(xiàng)目剛建立后,第一次構(gòu)建時(shí)需要選擇“重建 BSP 及項(xiàng)目”。以后的構(gòu)建中選擇“重新構(gòu)建”或“構(gòu)建項(xiàng)目”即可。另外,在替換了源代 碼中的文件后,需要選擇“重新構(gòu)建”來(lái)完成該項(xiàng)目的構(gòu)建。 4.配置虛擬機(jī)和目標(biāo)機(jī)代理 (1)制作X86啟動(dòng)盤(pán) 在 LambdaEDU 中依次點(diǎn)擊“工具”、“Bochs”、“制作虛擬機(jī)啟動(dòng)映象”。對(duì)啟動(dòng)盤(pán)進(jìn)行一些參數(shù)設(shè)置后(如下圖所示),系統(tǒng)將自動(dòng)為你生成一個(gè)PC 虛擬機(jī)的 啟動(dòng)盤(pán)映像。 (2)配置虛擬機(jī) 選擇使用的網(wǎng)絡(luò)適配器(網(wǎng)卡)后,點(diǎn)擊“確定”完成配置。 注意:如果計(jì)算機(jī)上有多網(wǎng)卡,請(qǐng)將其他網(wǎng)卡停用(包括 VMware 虛擬機(jī)添加的虛擬 網(wǎng)卡)。 (3)創(chuàng)建目標(biāo)機(jī)代理 配置好虛擬機(jī)后,創(chuàng)建目標(biāo)機(jī)代理:點(diǎn)擊LambdaEDU 左下方窗口中綠色的十字符號(hào),在彈出的窗口中選擇“基于TA 的連接方式”,并點(diǎn)擊“下一步”。 在彈出的“新目標(biāo)機(jī)連接配置中”的這些參數(shù),應(yīng)該與之前制作啟動(dòng)盤(pán)時(shí)設(shè)置的參數(shù)一致。 注意: 名字:輸入目標(biāo)機(jī)的名字(缺省是 default),注意如果和現(xiàn)有目標(biāo)機(jī)重名的話,改個(gè)名 字。 連接類型:默認(rèn)選擇 UDP IP地址:這里輸入目標(biāo)機(jī)(在本實(shí)驗(yàn)系統(tǒng)中是虛擬機(jī))的 IP地址; 最后點(diǎn)擊“確定”,在目標(biāo)機(jī)管理窗口中,可以看到新增加了一個(gè)名為default 的目標(biāo)機(jī) 節(jié)點(diǎn) (4)調(diào)試應(yīng)用 啟動(dòng)虛擬機(jī)。 虛擬機(jī)啟動(dòng)后的畫(huà)面如下(其中顯示的IP 地址創(chuàng)建虛擬機(jī)啟動(dòng)盤(pán)時(shí)填入的IP 地址)中設(shè)置的IP 地址): 在成功完成構(gòu)建的項(xiàng)目ucos_x86_demo 中的“pc386_elf_tra_debug”上點(diǎn)擊鼠標(biāo)右鍵,在彈出的菜單中選擇“調(diào)試”,啟動(dòng)調(diào)試器調(diào)試生成的程序: 第一次進(jìn)行調(diào)試/運(yùn)行,需要選擇目標(biāo)機(jī),如下圖,選擇“Default”,點(diǎn)擊“確定”,開(kāi) 始向目標(biāo)機(jī)(虛擬機(jī))下載應(yīng)用程序。程序下載完成后,會(huì)彈出一個(gè)“確認(rèn)透視圖切換”對(duì)話框,選擇“是”,切換到調(diào)試透 視圖。 調(diào)試的界面如下: 點(diǎn)擊綠色的按鈕,全速運(yùn)行。 注意:全速運(yùn)行后,程序不能夠被暫停和停止。 三、實(shí)驗(yàn)過(guò)程中遇到的問(wèn)題及體會(huì) 在設(shè)置IP地址時(shí),要求該IP地址與本計(jì)算機(jī)在同一個(gè)子網(wǎng)中,同時(shí)要求該 IP地址沒(méi)有被網(wǎng)絡(luò)上其他計(jì)算機(jī)使用。此外,通過(guò)構(gòu)建開(kāi)發(fā)環(huán)境,處次體驗(yàn)到了嵌入式開(kāi)發(fā)工作的樂(lè)趣。 實(shí)驗(yàn)二 任務(wù)的基本管理 一、實(shí)驗(yàn)?zāi)康?/p> 1.理解任務(wù)管理的基本原理,了解任務(wù)的各個(gè)基本狀態(tài)及其變遷過(guò)程; 2.掌握 uC/OS-II 中任務(wù)管理的基本方法(創(chuàng)建、啟動(dòng)、掛起、解掛任務(wù)); 3.熟練使用 uC/OS-II 任務(wù)管理的基本系統(tǒng)調(diào)用。 二、實(shí)驗(yàn)原理及程序結(jié)構(gòu) 1.實(shí)驗(yàn)設(shè)計(jì) 為了展現(xiàn)任務(wù)的各種基本狀態(tài)及其變遷過(guò)程,本實(shí)驗(yàn)設(shè)計(jì)了 Task0、Task1 兩個(gè)任務(wù): 任務(wù) Task0 不斷地掛起自己,再被任務(wù) Task1 解掛,兩個(gè)任務(wù)不斷地切換執(zhí)行。通過(guò)本實(shí)驗(yàn),讀者可以清晰地了解到任務(wù)在各個(gè)時(shí)刻的狀態(tài)以及狀態(tài)變遷的原因。2.運(yùn)行流程 描述如下: (1)系統(tǒng)經(jīng)歷一系列的初始化過(guò)程后進(jìn)入 boot_card()函數(shù),在其中調(diào)用 ucBsp_init()進(jìn) 行板級(jí)初始化后,調(diào)用 main()函數(shù); (2)main()函數(shù)調(diào)用 OSInit()函數(shù)對(duì) uC/OS-II 內(nèi)核進(jìn)行初始化,調(diào)用 OSTaskCreate 創(chuàng) 建起始任務(wù) TaskStart; (3)main()函數(shù)調(diào)用函數(shù) OSStart()啟動(dòng) uC/OS-II 內(nèi)核的運(yùn)行,開(kāi)始多任務(wù)的調(diào)度,執(zhí) 行當(dāng)前優(yōu)先級(jí)最高的就緒任務(wù) TaskStart;(4)TaskStart 完成如下工作: a、安裝時(shí)鐘中斷并初始化時(shí)鐘,創(chuàng)建 2 個(gè)應(yīng)用任務(wù); b、掛起自己(不再被其它任務(wù)喚醒),系統(tǒng)切換到當(dāng)前優(yōu)先級(jí)最高的就緒任務(wù)Task0。之后整個(gè)系統(tǒng)的運(yùn)行流程如下: ? t1 時(shí)刻,Task0 開(kāi)始執(zhí)行,它運(yùn)行到 t2 時(shí)刻掛起自己; ? t2 時(shí)刻,系統(tǒng)調(diào)度處于就緒狀態(tài)的優(yōu)先級(jí)最高任務(wù) Task1 執(zhí)行,它在 t3 時(shí)刻喚醒Task0,后者由于優(yōu)先級(jí)較高而搶占 CPU; ? Task0 執(zhí)行到 t4 時(shí)刻又掛起自己,內(nèi)核調(diào)度 Task1 執(zhí)行; ? Task1 運(yùn)行至 t5 時(shí)刻再度喚醒 Task0; ? …… 3.μC/OS-Ⅱ中的任務(wù)描述 一個(gè)任務(wù)通常是一個(gè)無(wú)限的循環(huán),由于任務(wù)的執(zhí)行是由操作系統(tǒng)內(nèi)核調(diào)度的,因此任務(wù)是絕不會(huì)返回的,其返回參數(shù)必須定義成 void。在μC/OS-Ⅱ中,當(dāng)一個(gè)運(yùn)行著的任務(wù)使一個(gè)比它優(yōu)先級(jí)高的任務(wù)進(jìn)入了就緒態(tài),當(dāng)前任務(wù)的 CPU 使用權(quán)就會(huì)被搶占,高優(yōu)先級(jí)任務(wù)會(huì)立刻得到 CPU 的控制權(quán)(在系統(tǒng)允許調(diào)度和任務(wù)切換的前提下)。μC/OS-Ⅱ可以管理多達(dá) 64 個(gè)任務(wù),但目前版本的μC/OS-Ⅱ有兩個(gè)任務(wù)已經(jīng)被系統(tǒng)占用了(即空閑任務(wù)和統(tǒng)計(jì)任務(wù))。必須給每個(gè)任務(wù)賦以不同的優(yōu)先級(jí),任務(wù)的優(yōu)先級(jí)號(hào)就是任務(wù)編號(hào)(ID),優(yōu)先級(jí)可以從 0 到 OS_LOWEST_PR10-2。優(yōu)先級(jí)號(hào)越低,任務(wù)的優(yōu)先級(jí)越高。μC/OS-Ⅱ總是運(yùn)行進(jìn)入就緒態(tài)的優(yōu)先級(jí)最高的任務(wù)。4.源程序說(shuō)明(1)TaskStart任務(wù) TaskStart 任務(wù)負(fù)責(zé)安裝操作系統(tǒng)的時(shí)鐘中斷服務(wù)例程、初始化操作系統(tǒng)時(shí)鐘,并創(chuàng)建所 有的應(yīng)用任務(wù): 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); 具體負(fù)責(zé)應(yīng)用任務(wù)創(chuàng)建的 TaskStartCreateTasks 函數(shù)代碼如下,它創(chuàng)建了兩個(gè)應(yīng)用任務(wù) Task0 和 Task1: void TaskStartCreateTasks(void){ INT8U i; for(i = 0;i < N_TASKS;i++)// Create tasks { TaskData[i] = i;// Each task will display itsown information } OSTaskCreate(Task0,(void *)&TaskData[0], &TaskStk[0][TASK_STK_SIZE1], 6);} TaskStart 任務(wù)完成上述操作后將自己掛起,操作系統(tǒng)將調(diào)度當(dāng)前優(yōu)先級(jí)最高的應(yīng)用任務(wù)Task0 運(yùn)行。(2)應(yīng)用任務(wù) 應(yīng)用任務(wù) Task0 運(yùn)行后將自己掛起,之后操作系統(tǒng)就會(huì)調(diào)度處于就緒狀態(tài)的優(yōu)先級(jí)最高的任務(wù),具體代碼如下: 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 } } 應(yīng)用任務(wù) Task1 運(yùn)行后將 Task0 喚醒,使其進(jìn)入到就緒隊(duì)列中: 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 */ } } 三、運(yùn)行及觀察應(yīng)用輸出信息 按照本實(shí)驗(yàn)手冊(cè)第一部分所描述的方法建立應(yīng)用項(xiàng)目并完成構(gòu)建,當(dāng)我們?cè)?LambdaEDU 調(diào)試器的控制下運(yùn)行構(gòu)建好的程序后,將看到在μC/OS-Ⅱ內(nèi)核的調(diào)度管理下,兩個(gè)應(yīng)用任務(wù)不斷切換執(zhí)行的情形: 四、本實(shí)驗(yàn)中用到的μC/OS-Ⅱ相關(guān)函數(shù) 4.1 OSTaskCreate() OSTaskCreate()建立一個(gè)新任務(wù)。任務(wù)的建立可以在多任務(wù)環(huán)境啟動(dòng)之前,也可以在 正在運(yùn)行的任務(wù)中建立。中斷處理程序中不能建立任務(wù)。一個(gè)任務(wù)必須為無(wú)限循環(huán)結(jié)構(gòu),且 不能有返回點(diǎn)。 OSTaskCreate()是為與先前的μC/OS 版本保持兼容,新增的特性在 OSTaskCreateExt()函數(shù)中。 無(wú)論用戶程序中是否產(chǎn)生中斷,在初始化任務(wù)堆棧時(shí),堆棧的結(jié)構(gòu)必須與 CPU 中斷后 寄存器入棧的順序結(jié)構(gòu)相同。詳細(xì)說(shuō)明請(qǐng)參考所用處理器的手冊(cè)。函數(shù)原型: INT8U OSTaskCreate(void(*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio); 參數(shù)說(shuō)明: task 是指向任務(wù)代碼首地址的指針。 pdata 指向一個(gè)數(shù)據(jù)結(jié)構(gòu),該結(jié)構(gòu)用來(lái)在建立任務(wù)時(shí)向任務(wù)傳遞參數(shù)。 ptos 為指向任務(wù)堆棧棧頂?shù)闹羔?。任?wù)堆棧用來(lái)保存局部變量,函數(shù)參數(shù),返回地址 以及任務(wù)被中斷時(shí)的 CPU 寄存器內(nèi)容。任務(wù)堆棧的大小決定于任務(wù)的需要及預(yù)計(jì)的中斷嵌 套層數(shù)。計(jì)算堆棧的大小,需要知道任務(wù)的局部變量所占的空間,可能產(chǎn)生嵌套調(diào)用的函數(shù),及中斷嵌套所需空間。如果初始化常量 OS_STK_GROWTH 設(shè)為 1,堆棧被設(shè)為從內(nèi)存高地址 向 低 地 址 增 長(zhǎng),此時(shí) ptos 應(yīng) 該 指 向任 務(wù)堆 棧 空 間 的 最 高 地 址。反 之,如 果OS_STK_GROWTH 設(shè)為 0,堆棧將從內(nèi)存的低地址向高地址增長(zhǎng)。prio 為任務(wù)的優(yōu)先級(jí)。每個(gè)任務(wù)必須有一個(gè)唯一的優(yōu)先級(jí)作為標(biāo)識(shí)。數(shù)字越小,優(yōu)先級(jí)越高。返回值: OSTaskCreate()的返回值為下述之一: ? OS_NO_ERR:函數(shù)調(diào)用成功。 ? OS_PRIO_EXIST:具有該優(yōu)先級(jí)的任務(wù)已經(jīng)存在。 ? OS_PRIO_INVALID:參數(shù)指定的優(yōu)先級(jí)大于 OS_LOWEST_PRIO。? OS_NO_MORE_TCB:系統(tǒng)中沒(méi)有 OS_TCB 可以分配給任務(wù)了。注意: 任務(wù)堆棧必須聲明為 OS_STK 類型。 在任務(wù)中必須調(diào)用μC/OS 提供的下述過(guò)程之一:延時(shí)等待、任務(wù)掛起、等待事件發(fā)生(等待信號(hào)量,消息郵箱、消息隊(duì)列),以使其他任務(wù)得到 CPU。用 戶 程 序 中 不 能 使 用 優(yōu) 先 級(jí) 0,1,2,3,以 及 OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。這些優(yōu)先級(jí)μC/OS 系統(tǒng) 保留,其余的 56 個(gè)優(yōu)先級(jí)提供給應(yīng)用程序。4.2 OSTaskSuspend() OSTaskSuspend()無(wú)條件掛起一個(gè)任務(wù)。調(diào)用此函數(shù)的任務(wù)也可以傳遞參數(shù) OS_PRIO_SELF,掛起調(diào)用任務(wù)本身。當(dāng)前任務(wù)掛起后,只有其他任務(wù)才能喚醒。任務(wù)掛起 后,系統(tǒng)會(huì)重新進(jìn)行任務(wù)調(diào)度,運(yùn)行下一個(gè)優(yōu)先級(jí)最高的就緒任務(wù)。喚醒掛起任務(wù)需要調(diào)用 函數(shù) OSTaskResume()。 任務(wù)的掛起是可以疊加到其他操作上的。例如,任務(wù)被掛起時(shí)正在進(jìn)行延時(shí)操作,那么 任務(wù)的喚醒就需要兩個(gè)條件:延時(shí)的結(jié)束以及其他任務(wù)的喚醒操作。又如,任務(wù)被掛起時(shí)正 在等待信號(hào)量,當(dāng)任務(wù)從信號(hào)量的等待對(duì)列中清除后也不能立即運(yùn)行,而必須等到被喚醒后。函數(shù)原型: INT8U OSTaskSuspend(INT8U prio);參數(shù)說(shuō)明: prio 為指定要獲取掛起的任務(wù)優(yōu)先級(jí),也可以指定參數(shù) OS_PRIO_SELF,掛起任務(wù)本 身。此時(shí),下一個(gè)優(yōu)先級(jí)最高的就緒任務(wù)將運(yùn)行。返回值: OSTaskSuspend()的返回值為下述之一: ? OS_NO_ERR:函數(shù)調(diào)用成功。 ? OS_TASK_ SUSPEND_IDLE:試圖掛起 μC/OS-II 中的空閑任務(wù)(Idle task)。此為非法操作。 ? OS_PRIO_INVALID :參數(shù)指定的優(yōu)先級(jí)大于 OS_LOWEST_PRIO 或沒(méi)有設(shè)定 ? OS_PRIO_SELF 的值。 ? OS_TASK_ SUSPEND _PRIO:要掛起的任務(wù)不存在。注意: 在程序中 OSTaskSuspend()和 OSTaskResume()應(yīng)該成對(duì)使用。用 OSTaskSuspend()掛起的任務(wù)只能用 OSTaskResume()喚醒。4.3 OSTaskResume() OSTaskResume()喚醒一個(gè)用 OSTaskSuspend()函數(shù)掛起的任務(wù)。OSTaskResume()也是唯一能“解掛”掛起任務(wù)的函數(shù)。函數(shù)原型: INT8UOSTaskResume(INT8U prio);參數(shù)說(shuō)明: prio 指定要喚醒任務(wù)的優(yōu)先級(jí)。返回值: OSTaskResume()的返回值為下述之一: ? OS_NO_ERR:函數(shù)調(diào)用成功。 ? OS_TASK_RESUME_PRIO:要喚醒的任務(wù)不存在。 ? OS_TASK_NOT_SUSPENDED:要喚醒的任務(wù)不在掛起狀態(tài)。 ? OS_PRIO_INVALID:參數(shù)指定的優(yōu)先級(jí)大于或等于 OS_LOWEST_PRIO。 五、實(shí)驗(yàn)過(guò)程中遇到的問(wèn)題及體會(huì) 實(shí)驗(yàn)過(guò)程中體會(huì)到了嵌入式開(kāi)發(fā)的樂(lè)趣,對(duì)上課老師所講的內(nèi)容有了進(jìn)一步的認(rèn)識(shí)與理解。17 實(shí)驗(yàn)三 信號(hào)量:哲學(xué)家就餐問(wèn)題的實(shí)現(xiàn) 一、實(shí)驗(yàn)?zāi)康?/p> 掌握在基于嵌入式實(shí)時(shí)操作系統(tǒng) uC/OS-II 的應(yīng)用中,任務(wù)使用信號(hào)量的一般原理。通 過(guò)經(jīng)典的哲學(xué)家就餐實(shí)驗(yàn),了解如何利用信號(hào)量來(lái)對(duì)共享資源進(jìn)行互斥訪問(wèn)。 二、實(shí)驗(yàn)原理及程序結(jié)構(gòu) 1.實(shí)驗(yàn)設(shè)計(jì) 掌握在基于嵌入式實(shí)時(shí)操作系統(tǒng) uC/OS-II 的應(yīng)用中,任務(wù)使用信號(hào)量的一般原理。通 過(guò)經(jīng)典的哲學(xué)家就餐實(shí)驗(yàn),了解如何利用信號(hào)量來(lái)對(duì)共享資源進(jìn)行互斥訪問(wèn)。2.源程序說(shuō)明 五個(gè)哲學(xué)家任務(wù)(ph1、ph2、ph3、ph4、ph5)主要有兩種過(guò)程:思考(即睡眠一段時(shí) 間)和就餐。每個(gè)哲學(xué)家任務(wù)在就餐前必須申請(qǐng)并獲得一左一右兩支筷子,就餐完畢后釋放 這兩支筷子。五個(gè)哲學(xué)家圍成一圈,每?jī)扇酥g有一支筷子。一共有五支筷子,在該實(shí)驗(yàn)中 用了五個(gè)互斥信號(hào)量來(lái)代表。每個(gè)任務(wù)的代碼都一樣,如下所示: void Task(void *pdata){ INT8U err;INT8U i;INT8U j; i=*(int *)pdata;j=(i+1)% 5; uC/OS-II 實(shí)驗(yàn)指導(dǎo)書(shū) 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 */ } } 操作系統(tǒng)配置 修改 uC_OS-II/OS_CFG.h: :: : #define OS_MAX_EVENTS 10 /*最多可以有 10 個(gè)事件*/ #define OS_MAX_FLAGS 5 /*最多可以有 5 個(gè)事件標(biāo)志*/ #define OS_MAX_MEM_PART 5 /*最多可以劃分 5 個(gè)內(nèi)存塊*/ #define OS_MAX_QS 2 /*最多可以使用 2 個(gè)隊(duì)列*/ #define OS_MAX_TASKS 8 /*最多可以創(chuàng)建 8 個(gè)任務(wù)*/ #define OS_LOWEST_PRIO 14 /*任務(wù)優(yōu)先級(jí)不可以大于 14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空閑任務(wù)堆棧大小*/ #define OS_TASK_STAT_EN 1 /*是否允許使用統(tǒng)計(jì)任務(wù)*/ #define OS_TASK_STAT_STK_SIZE 1024 /*統(tǒng)計(jì)任務(wù)堆棧大小*/ #define OS_FLAG_EN 1 /*是否允許使用事件標(biāo)志功能*/ #define OS_FLAG_WAIT_CLR_EN 1 /*是否允許等待清除事件標(biāo)志*/ #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 /*是否允許使用內(nèi)存管理的功能*/ #define OS_MUTEX_EN 0 /*是否允許使用互斥信號(hào)量的功能*/ #define OS_Q_EN 0 /*是否允許使用隊(duì)列功能*/ #define OS_SEM_EN 1 /*是否允許使用信號(hào)量功能*/ #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 /*設(shè)置每秒之內(nèi)的時(shí)鐘節(jié)拍數(shù)目*/ 三、運(yùn)行及觀察應(yīng)用輸出信息 開(kāi)始,所有的哲學(xué)家先處于 thinking 狀態(tài),然后都進(jìn)入 hungry 狀態(tài): 后首先獲得兩個(gè)信號(hào)量的 1、3 號(hào)哲學(xué)家開(kāi)始 eating,待他們釋放相關(guān)信號(hào)量之后,哲 學(xué)家 2、5、4 獲得所需的信號(hào)量并 eating: 應(yīng)用如此這般地循環(huán)執(zhí)行程序下去?? 四、本實(shí)驗(yàn)中用到的μC/OS-Ⅱ相關(guān)函數(shù) 4.1 OSSemCreate() OSSemCreate()函數(shù)建立并初始化一個(gè)信號(hào)量。信號(hào)量的作用如下: ? 允許一個(gè)任務(wù)和其他任務(wù)或者中斷同步 ? 取得設(shè)備的使用權(quán) ? 標(biāo)志事件的發(fā)生 函數(shù)原型: OS_EVENT *OSSemCreate((((WORD value))))參數(shù)說(shuō)明: value 參數(shù)是所建立的信號(hào)量的初始值,可以取 0 到 65535 之間的任何值。返回值: OSSemCreate()函數(shù)返回指向分配給所建立的信號(hào)量的控制塊的指針。如果沒(méi)有可用的 控制塊,OSSemCreate()函數(shù)返回空指針。注意: 必須先建立信號(hào)量,然后使用。4.2 OSSemPend() OSSemPend()函數(shù)用于任務(wù)試圖取得設(shè)備的使用權(quán),任務(wù)需要和其他任務(wù)或中斷同 步,任務(wù)需要等待特定事件的發(fā)生的場(chǎng)合。如果任務(wù)調(diào)用 OSSemPend()函數(shù)時(shí),信號(hào)量 的值大于零,OSSemPend()函數(shù)遞減該值并返回該值。如果調(diào)用時(shí)信號(hào)量等于零,OSSemPend()函數(shù)函數(shù)將任務(wù)加入該信號(hào)量的等待隊(duì)列。OSSemPend()函數(shù)掛起當(dāng)前 任務(wù)直到其他的任務(wù)或中斷置起信號(hào)量或超出等待的預(yù)期時(shí)間。如果在預(yù)期的時(shí)鐘節(jié)拍內(nèi)信 號(hào)量被置起,μC/OS-Ⅱ默認(rèn)最高優(yōu)先級(jí)的任務(wù)取得信號(hào)量恢復(fù)執(zhí)行。一個(gè)被 OSTaskSuspend()函數(shù)掛起的任務(wù)也可以接受信號(hào)量,但這個(gè)任務(wù)將一直保持掛起狀態(tài)直到通過(guò)調(diào)用 OSTaskResume()函數(shù)恢復(fù)任務(wù)的運(yùn)行。函數(shù)原型: :: : Void OSSemPend(OS_EVNNT *pevent, INT16U timeout, int8u *err);參數(shù)說(shuō)明: :: : pevent 是指向信號(hào)量的指針。該指針的值在建立該信號(hào)量時(shí)可以得到。(參考 OSSemCreate()函數(shù))。 Timeout 允許一個(gè)任務(wù)在經(jīng)過(guò)了指定數(shù)目的時(shí)鐘節(jié)拍后還沒(méi)有得到需要的信號(hào)量時(shí) 恢復(fù)就緒狀態(tài)。如果該值為零表示任務(wù)將持續(xù)地等待信號(hào)量,最大的等待時(shí)間為 65535 個(gè)時(shí) 鐘節(jié)拍。這個(gè)時(shí)間長(zhǎng)度并不是非常嚴(yán)格的,可能存在一個(gè)時(shí)鐘節(jié)拍的誤差。 Err 是指向包含錯(cuò)誤碼的變量的指針。OSSemPend()函數(shù)返回的錯(cuò)誤碼可能為下述幾 種: ? OS_NO_ERR :信號(hào)量不為零。 ? OS_TIMEOUT :信號(hào)量沒(méi)有在指定數(shù)目的時(shí)鐘周期內(nèi)被設(shè)置。 ? OS_ERR_PEND_ISR :從中斷調(diào)用該函數(shù)。雖然規(guī)定了不允許從中斷調(diào)用該函數(shù),但 μC/OS-Ⅱ仍然包含了檢測(cè)這種情況的功能。 ? OS_ERR_EVENT_TYPE :pevent 不是指向信號(hào)量的指針。返回值: 無(wú) 注意: 必須先建立信號(hào)量,然后使用。不允許從中斷調(diào)用該函數(shù)。 4.3 OSSemPost() OSSemPost()函數(shù)置起指定的信號(hào)量。如果指定的信號(hào)量是零或大于零,OSSemPost()函數(shù)遞增該信號(hào)量并返回。如果有任何任務(wù)在等待信號(hào)量,最高優(yōu)先級(jí)的任務(wù)將得到信 號(hào)量并進(jìn)入就緒狀態(tài)。任務(wù)調(diào)度函數(shù)將進(jìn)行任務(wù)調(diào)度,決定當(dāng)前運(yùn)行的任務(wù)是否仍然為最高 優(yōu)先級(jí)的就緒狀態(tài)的任務(wù)。函數(shù)原型: INT8U OSSemPost(OS_EVENT *pevent);參數(shù)說(shuō)明: pevent 是指向信號(hào)量的指針。該指針的值在建立該信號(hào)量時(shí)可以得到。(參考 OSSemCreate()函數(shù))。返回值: OSSemPost()函數(shù)的返回值為下述之一: ? OS_NO_ERR :信號(hào)量被成功地設(shè)置 ? OS_SEM_OVF :信號(hào)量的值溢出 ? OS_ERR_EVENT_TYPE :pevent 不是指向信號(hào)量的指針 注意: 必須先建立信號(hào)量,然后使用。4.4 OSTimeDly() OSTimeDly()將一個(gè)任務(wù)延時(shí)若干個(gè)時(shí)鐘節(jié)拍。如果延時(shí)時(shí)間大于 0,系統(tǒng)將立即進(jìn) 行任務(wù)調(diào)度。延時(shí)時(shí)間的長(zhǎng)度可從 0 到 65535 個(gè)時(shí)鐘節(jié)拍。延時(shí)時(shí)間 0 表示不進(jìn)行延時(shí),函 數(shù)將立即返回調(diào)用者。延時(shí)的具體時(shí)間依賴于系統(tǒng)每秒鐘有多少時(shí)鐘節(jié)拍(由文件 SO_CFG.H 中的常量 OS_TICKS_PER_SEC 設(shè)定)。函數(shù)原型: void OSTimeDly(INT16U ticks);參數(shù)說(shuō)明: ticks 為要延時(shí)的時(shí)鐘節(jié)拍數(shù)。返回值: 無(wú) 注意: 注意到延時(shí)時(shí)間 0 表示不進(jìn)行延時(shí)操作,而立即返回調(diào)用者。為了確保設(shè)定的延時(shí)時(shí)間,建議用戶設(shè)定的時(shí)鐘節(jié)拍數(shù)加 1。例如,希望延時(shí) 10 個(gè)時(shí)鐘節(jié)拍,可設(shè)定參數(shù)為 11。 五、實(shí)驗(yàn)過(guò)程中遇到的問(wèn)題及體會(huì) 在實(shí)驗(yàn)前要對(duì)該問(wèn)題進(jìn)行深入的理解,即五個(gè)哲學(xué)家任務(wù)(ph1、ph2、ph3、ph4、ph5)主要有兩種過(guò)程:思考(即睡眠一段時(shí)間)和就餐。每個(gè)哲學(xué)家任務(wù)在就餐前必須申請(qǐng)并獲得一左一右兩支筷子,就餐完畢后釋放這兩支筷子。五個(gè)哲學(xué)家圍成一圈,每?jī)扇酥g有一支筷子。只有理解了,才能更好的進(jìn)行實(shí)驗(yàn)。 計(jì)算機(jī)學(xué)院實(shí)驗(yàn)報(bào)告 課 程實(shí)驗(yàn)名稱 專 業(yè)班 級(jí)學(xué) 號(hào)學(xué)生姓名 操作系統(tǒng) 進(jìn)程的控制 計(jì)算機(jī)操作系統(tǒng) 131110196 鄒明鎮(zhèn) 嘉應(yīng)學(xué)院計(jì)算機(jī)學(xué)院 1305 一、實(shí)驗(yàn)?zāi)康?/p> 熟悉進(jìn)程的睡眠、同步、撤消等進(jìn)程控制方法 ? 利用 wait()來(lái)控制進(jìn)程執(zhí)行順序 ? 二、實(shí)驗(yàn)原理 1.sleep()使當(dāng)前的進(jìn)程睡眠,即當(dāng)前的進(jìn)程進(jìn)入阻塞態(tài)。2.wait()等待子進(jìn)程運(yùn)行結(jié)束。如果子進(jìn)程沒(méi)有完成,父進(jìn)程一直等待。wait()將調(diào)用進(jìn)程掛起,直至其子進(jìn)程因暫停或終止而發(fā)來(lái)軟中斷信號(hào)為止。如果在wait()前已有子進(jìn)程暫?;蚪K止,則調(diào)用進(jìn)程做適當(dāng)處理后便返回。系統(tǒng)調(diào)用格式: int wait(int *status);其中,status是用戶空間的地址。它的低8位反應(yīng)子進(jìn)程狀態(tài),為0表示子進(jìn)程正常結(jié)束,非0則表示出現(xiàn)了各種各樣的問(wèn)題;高8位則帶回了exit()的返回值。exit()返回值由系統(tǒng)給出。 核心對(duì) wait()作以下處理: (1)首先查找調(diào)用進(jìn)程是否有子進(jìn)程,若無(wú),則返回出錯(cuò)碼; (2)若找到一處于“僵死狀態(tài)”的子進(jìn)程,則將子進(jìn)程的執(zhí)行時(shí)間加到父進(jìn)程的執(zhí)行時(shí)間上,并釋放子進(jìn)程的進(jìn)程表項(xiàng); (3)若未找到處于“僵死狀態(tài)”的子進(jìn)程,則調(diào)用進(jìn)程便在可被中斷的優(yōu)先級(jí)上睡眠,等待其子進(jìn)程發(fā)來(lái)軟中斷信號(hào)時(shí)被喚醒。3.exit()終止進(jìn)程的執(zhí)行。系統(tǒng)調(diào)用格式: void exit(int status);其中,status是返回給父進(jìn)程的一個(gè)整數(shù),以備查考。 為了及時(shí)回收進(jìn)程所占用的資源并減少父進(jìn)程的干預(yù),UNIX/LINUX利用exit()來(lái)實(shí)現(xiàn)進(jìn)程的自我終止,通常父進(jìn)程在創(chuàng)建子進(jìn)程時(shí),應(yīng)在進(jìn)程的末尾安排一條exit(),使子進(jìn)程自我終止。exit(0)表示進(jìn)程正常終止,exit(1)表示進(jìn)程運(yùn)行有錯(cuò),異常終止。 如果調(diào)用進(jìn)程在執(zhí)行exit()時(shí),其父進(jìn)程正在等待它的終止,則父進(jìn)程可立即得到其返回的整數(shù)。核心須為exit()完成以下操作:(1)關(guān)閉軟中斷(2)回收資源(3)寫(xiě)記帳信息 (4)置進(jìn)程為“僵死狀態(tài)” /* 父進(jìn)程 */ int status;wait(&status);/*同步*/ printf(“Child process completed: %dn”, status);} else { /* 子進(jìn)程 */ printf(“Hello child!n”);return 0;} } 思考:這個(gè)程序中,子進(jìn)程的退出狀態(tài)值是多少? 5)利用 exit()設(shè)定子進(jìn)程的退出狀態(tài) #include main(){ int pid = fork();/*創(chuàng)建子進(jìn)程*/ if(pid > 0){ /* 父進(jìn)程 */ int status;wait(&status);/*同步*/ printf(“Child process completed: %d(%d, %d)n”, status, status/256, status%256);} else { /* 子進(jìn)程 */ printf(“Hello child!n”);exit(2);} } 思考:這個(gè)程序中,子進(jìn)程的退出狀態(tài)值是多少?如何獲得其低8位和高8位? 思考與練習(xí): 試回答每個(gè)程序后面的思考題。 四、實(shí)驗(yàn)環(huán)境 本次實(shí)驗(yàn)所使用的系統(tǒng)平臺(tái)Linux(Ubuntu)和相關(guān)軟件GCC。 3)同步 5)利用 exit()設(shè)定子進(jìn)程的退出狀態(tài)第二篇:操作系統(tǒng)實(shí)驗(yàn)報(bào)告
第三篇:操作系統(tǒng)第一次實(shí)驗(yàn)報(bào)告
第四篇:嵌入式操作系統(tǒng)實(shí)驗(yàn)報(bào)告
第五篇:操作系統(tǒng)實(shí)驗(yàn)報(bào)告