任務狀態轉換圖如下所示:
50.png (55.27 KB, 下載次數: 71)
下載附件
2013-7-18 20:03 上傳
一開始,任務在操作系統中是以函數代碼的形式存在的,在操作系統啟動的時候被加載到內存中,并未運行。并且,最開始的時候就緒表和就緒組是空的,或者說里面的內容都是0。很明顯,這時候任務在內存中睡眠,處于睡眠態。 如果不調用任務創建函數對任務進行操作,該任務將永遠處于睡眠態直到操作系統結束運行,被清除出內存。
任務的創建的學習中可以看到,任務創建的過程,首先分配一個空閑的TCB給任務,然后對該TCB的各個域進行賦值,對任務的堆棧進行初始化,其中,任務的代碼的地址被壓入堆棧。這為以后任務的運行做了充分的準備。就緒表和就緒組做了適當的處理,根據任務的優先級進行了設置。就緒TCB鏈表也插入了該TCB。
那么,若將任務刪除,如上圖所示,很明顯是任務的逆過程,應該將就緒表、就緒組進行逆向的操作,就緒鏈表中的相關TCB應該被移除,轉移到空閑TCB鏈表。和任務創建一,也要進行一些檢查,看任務是否符合被刪除的條件。
任務刪除還涉及一個請求刪除的問題,因此任務刪除看似簡單,實際上是比較復雜的一個過程。
任務刪除函數的參數只有一個,這個參數就是任務的優先級。 我們知道,任務的優先級是uC/OS-II標志任務的唯一標志,任務控制塊中雖然也有一個ID,但只是為了擴展使用。因此,任務刪除函數也可以理解為刪除指定優先級的任務。程序代碼如下所示:
51.png (48.77 KB, 下載次數: 67)
下載附件
2013-7-18 20:03 上傳
52.png (70.2 KB, 下載次數: 80)
下載附件
2013-7-18 20:03 上傳
從任務刪除的代碼中可以看到,任務刪除遠遠不像想象中那么簡單。刪除一個任務,就要照顧到該任務已經影響到的方方面面,否則系統就可能崩潰。由于任務刪除的代碼很長,而在執行的過程中一直在訪問全局變量,因此使系統不能響應中斷,破壞系統實時性。因此,在代碼的中間,使用巧妙的手段開一次中斷,過程如下:
(1)將任務調度鎖加1。
(2)開中斷
(3)執行一條空語句保證中斷有時間執行。
(4)關中斷
(5)將調度鎖減1,恢復原來的值。
刪除任務的代碼盡管復雜,但無外乎先進行參數的檢查,然后如果該任務在等待某些事件,就刪除等待的標志,之后對TCB中的值進行修改,對就緒表、就緒組、任務優先級指針表、就緒任務鏈表、空閑任務鏈表等重要的數據結構進行與創建任務相反的操作,只不過中間因為代碼執行時間過長,增加了臨時允許中斷的操作。
53.png (53.2 KB, 下載次數: 67)
下載附件
2013-7-18 20:03 上傳
關于任務的刪除,除了這個直接刪除任務的函數之外,還有一個非常重要的請求刪除任務的函數——OSTaskDelReq。
當以其他任務的優先級作為參數的時候,OSTaskDel粗暴地刪除了任務,這在某些情況下是有效的,但是卻不是必須這樣做。通知對方任務,告訴它要刪除你了,請任務自己刪除自己是一種更好的做法。因為這么做,任務可以在刪除自己之前先放棄自己使用的資源,如緩沖區、信號量、郵箱、隊列等。如果總是用OSTaskDel刪除一個任務,這個任務占用的資源不能得到釋放,系統就會產生內存泄漏,在內存泄漏累積到較大的時候,系統就會最后因為沒有可用的內存崩潰。
其實,OSTaskDelReq名稱雖然是請求,卻是集請求與響應于一段代碼內,該代碼的功能是請求刪除某任務和查看自己是否有任務要刪除自己。
例如,優先級為5的任務A調用OSTaskDelReq(10),請求刪除優先級為10的任務B。任務B調用OSTaskDelReq(OS_PRIO_SEL)并查看返回值,如果返回值為OS_ERR_TASK_DEL_REQ,說明有任務要求刪除自己了。任務B應該先釋放自己使用的資源,然后調用OSTaskDel(10)或OSTaskDel(OS_PRIO_SEL)來刪除自己。代碼如下所示:
54.png (46.21 KB, 下載次數: 58)
下載附件
2013-7-18 20:03 上傳
可見,請求刪除任務的代碼是比較少的,且前面一段是參數的檢查。后半部分的代碼根據參數不同,分別執行判斷是否有請求參數標志和給對方任務打上請求刪除標志。
|