|
下面這幾句話也是在網(wǎng)絡(luò)上看到,感覺寫的很通俗易懂供參考:
任務(wù)狀態(tài)
簡單分為運(yùn)行態(tài),就緒態(tài),阻塞態(tài)。
運(yùn)行態(tài):萬事俱備,不欠東風(fēng)(獲得CPU控制權(quán));
就緒態(tài):萬事俱備,只欠東風(fēng)(缺少CPU控制權(quán));
阻塞態(tài):萬事不俱備(等事件或信號),還欠東風(fēng)(缺少CPU控制權(quán));
(運(yùn)行態(tài):老板簽過字、銀行正常上班有錢------可以正常發(fā)薪水)
(就緒態(tài):老板沒簽字、銀行正常上班有錢 ----- 還需要等待)
(阻塞態(tài):老板沒簽字、銀行正常上班沒錢 ----- 還需要等待)
每個(gè)任務(wù)基本上都會(huì)游離于這三種狀態(tài)。
運(yùn)行到阻塞,就緒到運(yùn)行稱為任務(wù)切換過程。
從用戶的角度看,UCOSIII的任務(wù)一共有5種狀態(tài):
1、休眠態(tài):
任務(wù)已經(jīng)在CPU的flash中了,
但是還不受UCOSIII管理。
2、就緒態(tài):
系統(tǒng)為任務(wù)分配了任務(wù)控制塊,
并且任務(wù)已經(jīng)在就緒表中登記,
這時(shí)這個(gè)任務(wù)就具有了運(yùn)行的條件,
但是沒有獲得CPU 的使用權(quán)
此時(shí)任務(wù)的狀態(tài)就是就緒態(tài)。
3、運(yùn)行態(tài):
任務(wù)獲得CPU的使用權(quán),正在運(yùn)行。
4、等待態(tài):
正在運(yùn)行的任務(wù)需要等待一段時(shí)間,
或者等待某個(gè)事件,
這個(gè)任務(wù)就進(jìn)入了等待態(tài),
此時(shí)系統(tǒng)就會(huì)把CPU使用權(quán)轉(zhuǎn)交給別的任務(wù)。
5、中斷服務(wù)態(tài):
當(dāng)發(fā)送中斷,
當(dāng)前正在運(yùn)行的任務(wù)會(huì)被掛起,
CPU轉(zhuǎn)而去執(zhí)行中斷服務(wù)函數(shù),此時(shí)任務(wù)的任務(wù)狀態(tài)叫做中斷服務(wù)態(tài)。
白話任務(wù)堆棧、任務(wù)控制塊、任務(wù)函數(shù)
在多任務(wù)操作系統(tǒng)中創(chuàng)建任務(wù)時(shí),都需要指定該任務(wù)的堆棧大小,
那么這個(gè)堆棧的作用時(shí)什么呢?
什么情況下需要用到堆棧,以及大小不夠時(shí)會(huì)產(chǎn)生什么異常呢?
任務(wù)堆棧的作用:
1 任務(wù)處于運(yùn)行狀態(tài):
當(dāng)任務(wù)在運(yùn)行時(shí),
一般都會(huì)調(diào)用各式各樣的函數(shù),
而函數(shù)的局部變量,參數(shù),返回值是存在于函數(shù)棧幀里的,
每個(gè)函數(shù)都擁有獨(dú)立的棧幀,
各個(gè)棧幀使用的空間就是任務(wù)堆棧的空間。
所以任務(wù)堆棧的作用是用于保存函數(shù)在運(yùn)行/調(diào)用過程中的參數(shù)/局部變量。
(理解堆棧就是個(gè)倉庫倉庫里各種各樣的商品也就是各種功能不同函數(shù))
2 任務(wù)處于切換
當(dāng)運(yùn)行的任務(wù)被切換時(shí),需要保護(hù)現(xiàn)場(CPU中寄存器的值),
以便于下次恢復(fù)數(shù)據(jù)。
所以任務(wù)堆棧的作用是用于保存CPU中寄存器的值。
3
任務(wù)(低優(yōu)先級的)在運(yùn)行過程中,
隨時(shí)可能被切換,
所以CPU中寄存器的值入棧的棧位置是不確定的,
這取決于當(dāng)前任務(wù)的執(zhí)行情況。
4 堆棧溢出
若堆棧的空間設(shè)置太大,會(huì)浪費(fèi)內(nèi)存資源。
而設(shè)置得太小,則會(huì)出現(xiàn)堆棧溢出,在沒有MMU功能的操作系統(tǒng)中,
可能會(huì)導(dǎo)致系統(tǒng)奔潰。
所以,
需要根據(jù)任務(wù)的情況設(shè)置合適的堆棧大小。
同時(shí),應(yīng)避免使用遞歸調(diào)用函數(shù),
函數(shù)中局部變量的分配空間不能太大。
任務(wù)堆棧是任務(wù)的重要部分,
堆棧是在RAM中按照“先進(jìn)先出(FIFO)”的原則
組織的一塊連續(xù)的存儲空間。
為了滿足任務(wù)切換和響應(yīng)中斷時(shí)保存CPU寄存器中的內(nèi)容及
任務(wù)調(diào)用其它函數(shù)時(shí)的需要,
每個(gè)任務(wù)都應(yīng)該有自己的堆棧。
一般是這樣定義的
#define START_STK_SIZE 512 //堆棧大小
CPU_STK START_TASK_STK[START_STK_SIZE];//定義一個(gè)數(shù)組來作為任務(wù)堆棧
一般就是這樣定義的,
明白就行不能有壓力。
任務(wù)堆棧的大小是多少呢?
CPU_STK為 CPU_INT32U類型,
也就是 unsigned int類型,
為4字節(jié)的,
那么任務(wù)堆棧
START_TASK_STK的大小就為:512 X 4=2048字節(jié)!
任務(wù)如何才能切換回上一個(gè)任務(wù)
并且還能接著從上次被中斷的地方開始運(yùn)行?
這一點(diǎn)很重要系統(tǒng)是如何來切換任務(wù)的?
它是怎么知道某一個(gè)任務(wù)運(yùn)行到了那里?
它是怎么來記錄任務(wù)運(yùn)行過程中產(chǎn)生的數(shù)據(jù)?
這就是任務(wù)堆棧初始化的工作
這里是不是和剛學(xué)習(xí)單片機(jī)c51有些類似
org 0x0300
ljmp main
main: mov r0,r1
.....
.....
.....
.....
ajmp main
道理是一樣的
只不過在C 中我們直接定義了幾個(gè)大的ROM
每個(gè)ROM有是連續(xù)的存儲空間
好似這樣的結(jié)構(gòu)
................
. c51 .
. .
. .
. void main() .
. .
. .
. .
................
........................................................
. stm32 . .
. ucos - iii . .
........................................................
. void main() . . . .
. .void main() . . .
. . .void main() . .
. . . . void main() .
........................................................
51 的ROM 空間有過2K 、16K、64K 的
STM32 的空間就大的多了
這樣利用ucos iii 的組織能力就能在其內(nèi)部分割出來
相同或不相同的 void main(); 來
這其實(shí)就是任務(wù)堆棧的原型了。
至于在單片機(jī)內(nèi)部是如何分配的就不知道了。
知道堆棧的大概了那么
恢復(fù)現(xiàn)場就是重新讀取保存下來的CPU的內(nèi)部各個(gè)寄存器數(shù)據(jù)。
因此在創(chuàng)建一個(gè)新任務(wù)時(shí),
必須把系統(tǒng)啟動(dòng)這個(gè)任務(wù)時(shí)所需的CPU各個(gè)寄存器初始值事先存放在任務(wù)堆棧中。
這樣當(dāng)任務(wù)獲得CPU使用權(quán)時(shí),
就把任務(wù)堆棧的內(nèi)容復(fù)制到CPU的各個(gè)寄存器,
從而可以任務(wù)順利地啟動(dòng)并運(yùn)行。
把任務(wù)初始數(shù)據(jù)存放到任務(wù)堆棧的工作就叫做任務(wù)堆棧的初始化,
UCOSIII 提供了完成堆棧初始化的函數(shù):
OSTaskStkInit()。
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
用戶一般不會(huì)直接操作堆棧初始化函數(shù),
任務(wù)堆棧初始化函數(shù)由任務(wù)創(chuàng)建函數(shù)OSTaskCreate()調(diào)用。
不同的CPU對于的寄存器和對堆棧的操作方式不同,
因此在移植UCOSIII的時(shí)候需要
用戶根據(jù)各自所選的CPU來編寫任務(wù)堆棧初始化函數(shù)。
前面我們創(chuàng)建了一個(gè)任務(wù)堆棧,怎么使用這個(gè)任務(wù)堆棧?
作為任務(wù)創(chuàng)建函數(shù)OSTaskCreate()的參數(shù),
函數(shù)OSTaskCreate()如下:
void OSTaskCreate (OS_TCB *p_tcb,
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base, //任務(wù)堆;刂
CPU_STK_SIZE stk_limit, //任務(wù)堆棧棧深
CPU_STK_SIZE stk_size, //任務(wù)堆棧大小
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
其實(shí)看著有些復(fù)雜,其實(shí)很多參數(shù)都是一定的;
學(xué)習(xí)過后就理解
基礎(chǔ)東西很重要
特別是C 語言的基礎(chǔ)知識和算法
因?yàn)榛A(chǔ)的都是實(shí)際來處理具體問題的
即便上了系統(tǒng)
系統(tǒng)也只是起到一個(gè)調(diào)度的作用
平衡各個(gè)任務(wù)之間的運(yùn)行
函數(shù)OSTaskCreate()中的參數(shù)p_stk_base如何確定?
根據(jù)堆棧的增長方式,
堆棧有兩種增長方式:
向上增長:堆棧的增長方向從低地址向高地址增長。
向下增長:堆棧的增長方向從高地址向低地址增長
函數(shù)OSTaskCreate()中的參數(shù)p_stk_base是任務(wù)堆棧基地址,
那么如果CPU的堆棧是向上增長的話
那么基地址就&START_TASK_STK[0],
如果CPU堆棧是向下增長的話
基地址就是&START_TASK_STK[START_STK_SIZE-1]
STM32的堆棧是向下增長的!
寫了很多廢話,只是 為了了解任務(wù)堆棧
也寫的沒有趣味性了
失敗
|
評分
-
查看全部評分
|