|
本以為做個(gè)讀書(shū)筆記,誰(shuí)知不懂的太多,抄書(shū)好了。
來(lái)源:《嵌入式實(shí)時(shí)操作系統(tǒng)-uc/os原理與實(shí)踐》 盧友亮 編著
一:操作系統(tǒng)
1:操作系統(tǒng)基本功能:
任務(wù)管理
CPU管理
內(nèi)存管理 ----給任務(wù)分配內(nèi)存空間,內(nèi)存結(jié)束后釋放內(nèi)存空間
文件管理----對(duì)文件存儲(chǔ)器的存儲(chǔ)空間進(jìn)行組織,非配和回收,負(fù)責(zé)文件的存儲(chǔ),檢索,共享和保護(hù)
I/O設(shè)備管理
第二章: 實(shí)時(shí)操作系統(tǒng)(RTOS)
一:概述:
(一):定義
是指當(dāng)外界事件或數(shù)據(jù)產(chǎn)生時(shí),能夠接受并以足夠快的速度予以處理,其處理的結(jié)果又能在規(guī)定的時(shí)間之內(nèi)來(lái)控制生產(chǎn)過(guò)程或?qū)μ幚硐到y(tǒng)做出快速響應(yīng),調(diào)度一切可利用的資源完成實(shí)時(shí)任務(wù),并控制所有實(shí)時(shí)任務(wù)協(xié)調(diào)一致運(yùn)行的操作系統(tǒng)。
硬實(shí)時(shí)操作系統(tǒng):要求在規(guī)定的時(shí)間內(nèi)必須完成操作
軟實(shí)時(shí)操作系統(tǒng):只要按照任務(wù)的優(yōu)先級(jí),盡可能快地完成操作
(二):特征:
1:多任務(wù):系統(tǒng)中多個(gè)任務(wù)同時(shí)運(yùn)行。當(dāng)時(shí)cpu只有一個(gè),在某一個(gè)時(shí)刻,只有一個(gè)任務(wù)占有cpu,因此,多任務(wù)操作系統(tǒng)的核心任務(wù)之一是任務(wù)調(diào)度,為任務(wù)分配cpu時(shí)間。
2:多級(jí)中斷機(jī)制:
以確保對(duì)緊迫程度較高的實(shí)時(shí)時(shí)間進(jìn)行及時(shí)響應(yīng)和處理----例如:溫度超高的報(bào)警先處理
3:優(yōu)先級(jí)調(diào)度機(jī)制:
越緊迫的任務(wù)優(yōu)先級(jí)越高
任務(wù)管理模塊必須根據(jù)優(yōu)先級(jí)調(diào)度任務(wù),而又能保證任務(wù)在切換過(guò)程中不被破壞。
(三):任務(wù)
1:任務(wù)簡(jiǎn)介
任務(wù)有 睡眠,就緒,運(yùn)行,阻塞,掛起等多種狀態(tài)
典型的任務(wù)運(yùn)行方式是循環(huán)。
例1:
標(biāo)準(zhǔn)的任務(wù)結(jié)構(gòu):(用戶任務(wù))
void usertask(void *pParam) //參數(shù)是指針類(lèi)型的
{
int i=*((int *)pParam); //將指針強(qiáng)制轉(zhuǎn)換為指向整數(shù)類(lèi)型的指針,然后取改指針?biāo)傅膬?nèi)容,將它賦值給一個(gè)局部變量i
for( ; ; ) //進(jìn)入無(wú)限循環(huán)
printf("\n\r%d\n",i++); //在循環(huán)體打印輸出當(dāng)前的計(jì)數(shù)值i
OSTimeDly(OS_TICKS_PER_SEC); //調(diào)用操作系統(tǒng)演示函數(shù),延時(shí)1s。1s后又可以獲得運(yùn)行,繼續(xù)循環(huán)
}
注:OSTimeDly首先將本任務(wù) 阻塞掉,這樣,即使該任務(wù)優(yōu)先級(jí)最高,也可以讓低優(yōu)先級(jí)的任務(wù)獲得運(yùn)行的機(jī)會(huì)。操作系統(tǒng)1s后使這個(gè)任務(wù)重新就緒,重新得到運(yùn)行。
2:多任務(wù):
優(yōu)點(diǎn):可以大大提高cpu的利用率,使應(yīng)用程序分成多個(gè)程序模塊,實(shí)現(xiàn)模塊化,應(yīng)用程序更易于設(shè)計(jì)和維護(hù)
例如:在ARM采集處理系統(tǒng)中,同時(shí)采集16路信號(hào),又同時(shí)對(duì)多信號(hào)進(jìn)行處理和傳輸,
可以創(chuàng)建16個(gè)任務(wù)負(fù)責(zé)16路信號(hào)的采集,
創(chuàng)建一個(gè)任務(wù)對(duì)信號(hào)進(jìn)行處理,
再創(chuàng)建一個(gè)任務(wù)負(fù)責(zé)數(shù)據(jù)的傳輸。
例:2:
int main(int argc, char **argv)
{
int p[2];
p[0]=0;
p[1]=100;
OSInit(); //對(duì)ucosii內(nèi)核進(jìn)行初始化
OSTaskCreate(TaskStart,0,&TaskStk[0][TASK_STK_SIZE-1],TaskStart_Prio); //創(chuàng)建一個(gè)設(shè)置時(shí)鐘中斷的任務(wù)
//創(chuàng)建用戶任務(wù),任務(wù)代碼是例1的usertask,參數(shù)是p,即指向p[0]的指針,優(yōu)先級(jí)是5
OSTaskCreate(usertask,p,&TaskStk[2][TASK_STK_SIZE-1],5);
//創(chuàng)建用戶任務(wù),任務(wù)代碼是例1的usertask,參數(shù)是p+1,即指向p[1]的指針,優(yōu)先級(jí)是6
OSTaskCreate(usertask,p+1,&TaskStk[3][TASK_STK_SIZE-1],6);
OSStart(); //開(kāi)始啟動(dòng)多任務(wù)
return 0;
}
分析:
兩個(gè)用戶任務(wù)的優(yōu)先級(jí)雖然不同,但是都執(zhí)行延時(shí)操作,也就是說(shuō)主動(dòng)放棄cpu,因此可以輪流運(yùn)行。
(如果沒(méi)有執(zhí)行延時(shí)操作,把自己阻塞起來(lái),在高優(yōu)先級(jí)任務(wù)結(jié)束前,低優(yōu)先級(jí)的任務(wù)是不能得到運(yùn)行的)
運(yùn)行結(jié)果: 第一個(gè)任務(wù)的參數(shù)是0,從0開(kāi)始計(jì)數(shù),第二個(gè)任務(wù)的參數(shù)是100,從100開(kāi)始計(jì)數(shù)。
兩個(gè)任務(wù)輪流輸出結(jié)果到屏幕,多任務(wù)被調(diào)度運(yùn)行了。
0
100
1
101
2
102
3
103
3:任務(wù)狀態(tài):

1:睡眠態(tài):
在調(diào)用 OSTaskCreate(任務(wù)創(chuàng)建函數(shù))創(chuàng)建之前,處于睡眠狀態(tài)。
睡眠狀態(tài)的任務(wù)是不會(huì)運(yùn)行的,操作系統(tǒng)也不會(huì)為他設(shè)置運(yùn)行而準(zhǔn)備的數(shù)據(jù)結(jié)構(gòu),沒(méi)有給它配置任務(wù)模塊。
2:就緒態(tài)
當(dāng)操作系統(tǒng)調(diào)用 OSTaskCreate()創(chuàng)建一個(gè)任務(wù)后,任務(wù)進(jìn)入就緒態(tài)。
圖中可以看到,任務(wù)也可以從其他狀態(tài)進(jìn)入就緒態(tài)。
處于就緒態(tài)的任務(wù) :操作系統(tǒng)已經(jīng)為其運(yùn)行配置好了任務(wù)控制模塊等數(shù)據(jù)結(jié)構(gòu)。
當(dāng)沒(méi)有比它優(yōu)先級(jí)更高的任務(wù)或者優(yōu)先級(jí)更高的任務(wù)處于阻塞態(tài)的時(shí)候,就可以被系統(tǒng)調(diào)度進(jìn)入運(yùn)行態(tài),操作系統(tǒng)是調(diào)用任務(wù)切換函數(shù)完成的。
3:運(yùn)行態(tài):
運(yùn)行態(tài)是任務(wù)真正占有cpu,得到運(yùn)行。這時(shí)運(yùn)行的代碼就是任務(wù)的代碼,如usertask。
處于運(yùn)行態(tài)的任務(wù)如果運(yùn)行完成,就會(huì)進(jìn)入睡眠態(tài)。
如果更高優(yōu)先級(jí)的任務(wù)搶占了cpu,就會(huì)轉(zhuǎn)到就緒態(tài)。
如果 因?yàn)榈却骋皇录绲却?s的時(shí)間,OSTimeDly(OS_TICKS_PER_SEC); 需要暫時(shí)放棄cpu的使用權(quán)而讓其他任務(wù)得到運(yùn)行,就進(jìn)入阻塞態(tài)。
當(dāng)由于中斷的到來(lái)而使cpu進(jìn)入中斷服務(wù)函數(shù)ISR,必然使正在運(yùn)行過(guò)得任務(wù)放棄cpu而轉(zhuǎn)入中斷服務(wù)程序,這是被中斷的程序就會(huì)被掛起而進(jìn)入掛起態(tài)。
4:阻塞態(tài):
阻塞態(tài)對(duì)于操作系統(tǒng)的調(diào)度、任務(wù)的協(xié)調(diào)運(yùn)行時(shí)很重要的。
圖中所示:并不是只有一個(gè)高優(yōu)先級(jí)的任務(wù)在運(yùn)行,是因?yàn)閡sertask在沒(méi)有事情可做,在等待1s的時(shí)候,不是強(qiáng)行運(yùn)行代碼,而使把自己阻塞起來(lái),使操作系統(tǒng)可以調(diào)度其他的任務(wù)。OSTimeDly(OS_TICKS_PER_SEC);
當(dāng)任務(wù)在等待某些還沒(méi)有被釋放的資源或等待一定時(shí)間的時(shí)候,要阻塞起來(lái),等到條件滿足的時(shí)候再重新回到就緒態(tài),又能被操作系統(tǒng)調(diào)度以進(jìn)入運(yùn)行態(tài)。這是實(shí)時(shí)操作系統(tǒng)必須實(shí)現(xiàn)的功能之一。
注意:錯(cuò)誤:一些不理解操作系統(tǒng)的讀者編程時(shí)候,在等待的時(shí)候常常使用for循環(huán),不停的執(zhí)行代碼而使cpu的利用率暴增,使系統(tǒng)的運(yùn)行,甚至造成死機(jī),十分惡劣。這樣不可取。
5:掛起態(tài):
當(dāng)任務(wù)在運(yùn)行時(shí),因?yàn)?font color="#ff00">中斷的發(fā)生(例如定時(shí)器中斷每個(gè)時(shí)鐘滴答)中斷一次,被剝奪cpu的使用權(quán)而進(jìn)入掛起狀。在中斷返回的時(shí)候,若該任務(wù)還是最高優(yōu)先級(jí)的,則恢復(fù)運(yùn)行。
如果不是這樣,就回到就緒態(tài)。
4:任務(wù)切換:-----Context Switch
任務(wù)切換時(shí)暫停一個(gè)任務(wù)的運(yùn)行,云更新另一個(gè)處于就緒態(tài)的任務(wù),暫停一個(gè)任務(wù),以后又能恢復(fù)運(yùn)行,必須考慮將這個(gè)任務(wù)的信息保存,而恢復(fù)運(yùn)行的時(shí)候需要將這些信息恢復(fù)到運(yùn)行環(huán)境。
因此,任務(wù)切換必須做環(huán)境的保存和恢復(fù)的操作。
環(huán)境的保存和恢復(fù)與任務(wù)有關(guān),業(yè)余任務(wù)運(yùn)行的硬件環(huán)境有關(guān)(PC和ARM有不同的寄存器,所以不同,因此涉及到匯編語(yǔ)言實(shí)現(xiàn)的最底層代碼。---因此需要一定的計(jì)算機(jī)原理或者嵌入式系統(tǒng)的基本知識(shí)。
多任務(wù)的關(guān)鍵在于.如何將調(diào)度,ucos采用的是可剝奪優(yōu)先級(jí)調(diào)度算法。
多任務(wù)下,個(gè)任務(wù)還要按照一定的次序運(yùn)行,因此存在同步問(wèn)題,因此引入了信號(hào)量的改年來(lái)進(jìn)行同步。
人物間有相互通信的需求,因此操作系統(tǒng)需要有郵箱、消息等用于通信的數(shù)據(jù)結(jié)構(gòu),以便多任務(wù)通信。
多個(gè)任務(wù)可能真多有限的資源而不發(fā)生沖突,因此操作系統(tǒng)還需要管理各任務(wù),使他們能夠充分利用資源而不發(fā)生沖突,因此又產(chǎn)生了互斥,死鎖等概念。
5:可重入函數(shù) 與 不可重入函數(shù) (任務(wù)應(yīng)該調(diào)用可重入函數(shù))
可重入函數(shù): 指一個(gè)函數(shù)可以被多個(gè)任務(wù)調(diào)用。(不需要擔(dān)心在任務(wù)切換的過(guò)程中,代碼的執(zhí)行會(huì)摻和啥呢個(gè)錯(cuò)誤的結(jié)果)
不可重入函數(shù):如果可能產(chǎn)生錯(cuò)誤的結(jié)果,就是不可重入函數(shù)。
例3:
啟動(dòng)兩個(gè)用戶任務(wù):usertask1和usertask2 兩個(gè)任務(wù)都調(diào)用add2函數(shù)(將返回兩個(gè)參數(shù)相加的結(jié)果),使用了全局變量a和b。
void usertask1(void *pParam)
{
int sum;
for( ; ; )
{
printf("\ntask% call add2(1,2)\n",1);
sum=add2(1,2);
printf("\ntask% call add2(1,2) solution is %d\n",1,sum);
}
}
void usertask2(void *pParam)
{
int sum;
for( ; ; )
{
printf("\ntask% call add2(100,200)\n",2);
sum=add2(100,200);
printf("\ntask% call add2(100,200) solution is %d\n",2,sum);
}
}
a:
使用不可重入函數(shù)得到的錯(cuò)誤結(jié)果:
int a,b; //定義全局變量,各個(gè)任務(wù)都可以訪問(wèn)的全局變量
int add2(int p1,int,p2) //函數(shù)add2()實(shí)現(xiàn)對(duì)兩個(gè)參數(shù)相加,返回結(jié)果,因?yàn)槭褂昧巳肿兞,所以在任?wù)切換過(guò)程中,他得知可能改變
{
a=p1;
b=p2;
OSTimeDly(OS_TICKS_PER_SEC); //延時(shí)1s任務(wù)被阻塞,以保證任務(wù)被切換
return(a+b); //返回相加結(jié)果
}
運(yùn)行結(jié)果:
task1 call add2(1,2) solution is 300
task2 call add2(100,200) solution is 3
task1 call add2(1,2) solution is 300
task2 call add2(100,200) solution is 3
分析:
結(jié)果完全錯(cuò)誤。
usertask1的優(yōu)先級(jí)為5,usertask2的優(yōu)先級(jí)為6。
操作系統(tǒng)首先調(diào)度usertask1運(yùn)行,對(duì)變量a、b進(jìn)行賦值,運(yùn)行結(jié)果為a=1,b=2.
然后調(diào)用OSTimeDly(OS_TICKS_PER_SEC);延時(shí),usertask1被阻塞,操作系統(tǒng)進(jìn)行一次任務(wù)切換。
usertask2得到尋釁,對(duì)a,b進(jìn)行賦值,運(yùn)行結(jié)果為a=100,b=200.
在經(jīng)過(guò)一段延時(shí)后,usertask1被喚醒,重新得到運(yùn)行,返回a+b的結(jié)果,于是有了1+2=300的錯(cuò)誤結(jié)果。
打印出第一行后,usertask1仍然要進(jìn)行循環(huán),于是又調(diào)用add2,又給a、b進(jìn)行賦值,運(yùn)行結(jié)果為a=1,b=2,
再延時(shí),進(jìn)入usertask2延時(shí)結(jié)束得到運(yùn)行,打印出了第二行100+200=3的錯(cuò)誤結(jié)果。
b:使用可重入函數(shù)得到正確結(jié)果
int add2(int p1,int,p2) //函數(shù)add2()實(shí)現(xiàn)對(duì)兩個(gè)參數(shù)相加,返回結(jié)果,因?yàn)槭褂昧巳肿兞,所以在任?wù)切換過(guò)程中,他得知可能改變
{
int a,b;
a=p1;
b=p2;
OSTimeDly(OS_TICKS_PER_SEC); //延時(shí)1s任務(wù)被阻塞,以保證任務(wù)被切換
return(a+b); //返回相加結(jié)果
}
運(yùn)行結(jié)果:
task1 call add2(1,2) solution is 3
task2 call add2(100,200) solution is 300
task1 call add2(1,2) solution is 3
task2 call add2(100,200) solution is 300
分析:
結(jié)果正確。
原因是add2函數(shù)采用了可重入代碼----------因此在實(shí)時(shí)多任務(wù)操作系統(tǒng)中,公用函數(shù)口用該采用可重入代碼。
|
|