任務
1 基本概念
從系統的角度看,任務是競爭系統資源的最小運行單元。任務能夠使用或等待CPU、使用內存空間等系統資源,並獨立於其它任務運行。編程
Huawei LiteOS的任務模塊能夠給用戶提供多個任務,實現了任務之間的切換和通訊,幫助用戶管理業務程序流程。這樣用戶能夠將更多的精力投入到業務功能的實現中。函數
Huawei LiteOS是一個支持多任務的操做系統。在Huawei LiteOS中,一個任務表示一個線程。測試
Huawei LiteOS中的任務是搶佔式調度機制,同時支持時間片輪轉調度方式。spa
高優先級的任務可打斷低優先級任務,低優先級任務必須在高優先級任務阻塞或結束後才能獲得調度。操作系統
Huawei LiteOS的任務一共有32個優先級(0-31),最高優先級爲0,最低優先級爲31。線程
2 任務相關概念
2.1 任務狀態
Huawei LiteOS系統中的每一任務都有多種運行狀態。系統初始化完成後,建立的任務就能夠在系統中競爭必定的資源,由內核進行調度。3d
任務狀態一般分爲如下四種:指針
- 就緒(Ready):該任務在就緒列表中,只等待CPU。
- 運行(Running):該任務正在執行。
- 阻塞(Blocked):該任務不在就緒列表中。包含任務被掛起、任務被延時、任務正在等待信號量、讀寫隊列或者等待讀寫事件等。
- 退出態(Dead):該任務運行結束,等待系統回收資源。
圖 3-1 任務狀態示意圖 code
- 就緒態-》運行態
任務建立後進入就緒態,發生任務切換時,就緒列表中最高優先級的任務被執行,從而進入運行態,但此刻該任務依舊在就緒列表中。blog
- 運行態→阻塞態:
正在運行的任務發生阻塞(掛起、延時、讀信號量等待)時,該任務會從就緒列表中刪除,任務狀態由運行態變成阻塞態,而後發生任務切換,運行就緒列表中剩餘最高優先級任務。
- 阻塞態→就緒態(阻塞態→運行態):
阻塞的任務被恢復後(任務恢復、延時時間超時、讀信號量超時或讀到信號量等),此時被恢復的任務會被加入就緒列表,從而由阻塞態變成就緒態;此時若是被恢復任務的優先級高於正在運行任務的優先級,則會發生任務切換,將該任務由就緒態變成運行態。
- 阻塞態→退出態
阻塞的任務調用刪除接口,任務狀態由阻塞態變爲退出態。
2.2 任務ID
任務ID,在任務建立時經過參數返回給用戶,做爲任務的一個很是重要的標識。用戶能夠經過任務ID對指定任務進行任務掛起、任務恢復、查詢任務名等操做。
2.3 任務優先級
優先級表示任務執行的優先順序。任務的優先級決定了在發生任務切換時即將要執行的任務。在就緒列表中的最高優先級的任務將獲得執行。
2.4 任務入口函數
每一個新任務獲得調度後將執行的函數。該函數由用戶實現,在任務建立時,經過任務建立結構體指定。
2.5 任務控制塊TCB
每個任務都含有一個任務控制塊(TCB)。 TCB包含了任務上下文棧指針(stack pointer)、任務狀態、任務優先級、任務ID、任務名、任務棧大小等信息。 TCB能夠反映出每一個任務運行狀況。
2.6 任務棧
每個任務都擁有一個獨立的棧空間,咱們稱爲任務棧。棧空間裏保存的信息包含局部變量、寄存器、函數參數、函數返回地址等。任務在任務切換時會將切出任務的上下文信息保存在自身的任務棧空間裏面,以便任務恢復時還原現場,從而在任務恢復後在切出點繼續開始執行。
2.7 任務切換
任務切換包含獲取就緒列表中最高優先級任務、切出任務上下文保存、切入任務上下文恢復等動做。
3 運做機制
Huawei LiteOS任務管理模塊提供任務建立、任務延時、任務掛起和任務恢復、鎖任務調度和解鎖任務調度、根據任務控制塊查詢任務ID、根據ID查詢任務控制塊信息功能。
在用戶建立任務以前,系統會先申請任務控制塊須要的內存空間,若是系統可用的內存空間小於其所須要的內存空間,任務模塊就會初始化失敗。若是任務初始化成功,
用戶建立任務時,系統會將任務棧進行初始化,預置上下文。此外,系統還會將「任務入口函數」地址放在相應位置。這樣在任務第一次啓動進入運行態時,將會執行「任務入口函數」。
4. 開發指導
4.1 使用場景
任務建立後,內核能夠執行鎖任務調度,解鎖任務調度,掛起,恢復,延時等操做,同時也能夠設置任務優先級,獲取任務優先級。任務結束的時候,若是任務的狀態是自刪除狀態(LOS_TASK_STATUS_DETACHED),則進行當前任務自刪除操做。
4.2 功能
Huawei LiteOS 系統中的任務管理模塊爲用戶提供下面幾種功能。
功能分類 | 接口名 | 描述 |
---|---|---|
任務的建立和刪除 | LOS_TaskCreateOnly | 建立任務,並使該任務進入suspend狀態,並不調度 |
~ | LOS_TaskCreate | 建立任務,並使該任務進入ready狀態,並調度 |
~ | LOS_TaskDelete | 刪除指定的任務 |
~ | LOS_TaskDelete | 刪除指定的任務 |
任務狀態控制 | LOS_TaskResume | 恢復掛起的任務 |
~ | LOS_TaskSuspend | 掛起指定的任務 |
~ | LOS_TaskDelay | 任務延時等待 |
~ | LOS_TaskYield | 顯式放權,調整指定優先級的任務調度順序 |
任務調度的控制 | LOS_TaskLock | 鎖任務調度 |
~ | LOS_TaskUnlock | 解鎖任務調度 |
任務優先級的控制 | LOS_CurTaskPriSet | 設置當前任務的優先級 |
~ | LOS_TaskPriSet | 設置指定任務的優先級 |
~ | LOS_TaskPriGet | 獲取指定任務的優先級 |
任務信息獲取 | LOS_CurTaskIDGet | 獲取當前任務的ID |
~ | LOS_TaskInfoGet | 獲取指定任務的信息 |
4.3 開發流程
以建立任務爲例,講解開發流程。
- 在los_config.h中配置任務模塊。
配置LOSCFG_BASE_CORE_TSK_LIMIT系統支持最大任務數,這個能夠根據需求本身配置。
配置LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE IDLE任務棧大小,這個默認便可。
配置LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE默認任務棧大小,用戶根據本身的需求進行配置,在用戶建立任務時,能夠進行鍼對性設置。
配置LOSCFG_BASE_CORE_TIMESLICE時間片開關爲YES。
配置LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT時間片,根據實際狀況本身配置。
配置LOSCFG_BASE_CORE_TSK_MONITOR任務監測模塊裁剪開關,可選擇是否打開。
- 鎖任務LOS_TaskLock,鎖住任務,防止高優先級任務調度。
- 建立任務LOS_TaskCreate。
- 解鎖任務LOS_TaskUnlock,讓任務按照優先級進行調度。
- 延時任務LOS_TaskDelay,任務延時等待。
- 掛起指定的任務LOS_TaskSuspend,任務掛起等待恢復操做。
- 恢復掛起的任務LOS_TaskResume。
4.4 TASK 狀態
Huawei LiteOS任務的大多數狀態由內核維護,惟有自刪除狀態對用戶可見,須要用戶在建立任務時傳入:
序號 | 定義 | 實際數值 | 描述 |
---|---|---|---|
1 | LOS_TASK_STATUS_DETACHED | 0x0080 | 任務是自刪除的 |
4.5 TASK 錯誤碼
對任務存在失敗可能性的操做,包括建立任務、刪除任務、掛起任務、恢復任務、延時任務等等,均須要返回對應的錯誤碼,以便快速定位錯誤緣由。
序 號 | 定義 | 實際數值 | 描述 | 參考解決方案 |
---|---|---|---|---|
1 | LOS_ERRNO_TSK_NO_MEMORY | 0x03000200 | 內存空間不足 | 分配更大的內存空間 |
2 | LOS_ERRNO_TSK_PTR_NULL | 0x02000201 | 任務參數爲空 | 檢查任務參數 |
3 | LOS_ERRNO_TSK_STKSZ_NOT_ALIGN | 0x02000202 | 任務棧大小未對齊 | 對齊任務棧 |
4 | LOS_ERRNO_TSK_PRIOR_ERROR | 0x02000203 | 不正確的任務優先級 | 檢查任務優先級 |
5 | LOS_ERRNO_TSK_ENTRY_NULL | 0x02000204 | 任務入口函數爲空 | 定義任務入口函數 |
7 | LOS_ERRNO_TSK_STKSZ_TOO_SMAL | 0x02000206 | 任務棧過小 | 擴大任務棧 |
8 | LOS_ERRNO_TSK_ID_INVALID | 0x02000207 | 無效的任務ID | 檢查任務ID |
9 | LOS_ERRNO_TSK_ALREADY_SUSPENDED | 0x02000208 | 任務已經被掛起 | 等待這個任務被恢復後,再去嘗試掛起這個任務 |
10 | LOS_ERRNO_TSK_NOT_SUSPENDED | 0x02000209 | 任務未被掛起 | 掛起這個任務 |
11 | LOS_ERRNO_TSK_NOT_CREATED | 0x0200020a | 任務未被建立 | 建立這個任務 |
12 | LOS_ERRNO_TSK_DELETE_LOCKED | 0x0300020b | 刪除任務時,任務處於被鎖狀態 | 等待解鎖任務以後再進行刪除操做 |
13 | LOS_ERRNO_TSK_MSG_NONZERO | 0x0200020c | 任務信息非零 | 暫不使用該錯誤碼 |
14 | LOS_ERRNO_TSK_DELAY_IN_INT | 0x0300020d | 中斷期間,進行任務延時 | 等待退出中斷後再進行延時操做 |
15 | LOS_ERRNO_TSK_DELAY_IN_LOCK | 0x0200020e | 任務被鎖的狀態下,進行延時 | 等待解鎖任務以後再進行延時操做 |
16 | LOS_ERRNO_TSK_YIELD_INVALID_TASK | 0x0200020f | 將被排入行程的任務是無效的 | 檢查這個任務 |
17 | LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK | 0x02000210 | 沒有或者僅有一個可用任務能進行行程安排 | 增長任務數 |
18 | LOS_ERRNO_TSK_TCB_UNAVAILABLE | 0x02000211 | 沒有空閒的任務控制塊可用 | 增長任務控制塊數量 |
19 | LOS_ERRNO_TSK_HOOK_NOT_MATCH | 0x02000212 | 任務的鉤子函數不匹配 | 暫不使用該錯誤碼 |
20 | LOS_ERRNO_TSK_HOOK_IS_FULL | 0x02000213 | 任務的鉤子函數數量超過界限 | 暫不使用該錯誤碼 |
21 | LOS_ERRNO_TSK_OPERATE_IDLE | 0x02000214 | 這是個IDLE任務 | 檢查任務ID,不要試圖操做IDLE任務 |
22 | LOS_ERRNO_TSK_SUSPEND_LOCKED | 0x03000215 | 將被掛起的任務處於被鎖狀態 | 等待任務解鎖後再嘗試掛起任務 |
23 | LOS_ERRNO_TSK_FREE_STACK_FAILED | 0x02000217 | 任務棧free失敗 | 該錯誤碼暫不使用 |
24 | LOS_ERRNO_TSK_STKAREA_TOO_SMALL | 0x02000218 | 任務棧區域過小 | 該錯誤碼暫不使用 |
25 | LOS_ERRNO_TSK_ACTIVE_FAILED | 0x03000219 | 任務觸發失敗 | 建立一個IDLE任務後執行任務轉換 |
26 | LOS_ERRNO_TSK_CONFIG_TOO_MANY | 0x0200021a | 過多的任務配置項 | 該錯誤碼暫不使用 |
27 | LOS_ERRNO_TSK_CP_SAVE_AREA_NOT_ALIGN | 0x0200021b | 暫無 | 該錯誤碼暫不使用 |
28 | LOS_ERRNO_TSK_MSG_Q_TOO_MANY | 0x0200021d | 暫無 | 該錯誤碼暫不使用 |
29 | LOS_ERRNO_TSK_CP_SAVE_AREA_NULL | 0x0200021e | 暫無 | 該錯誤碼暫不使用 |
30 | LOS_ERRNO_TSK_SELF_DELETE_ERR | 0x0200021f | 暫無 | 該錯誤碼暫不使用 |
31 | LOS_ERRNO_TSK_STKSZ_TOO_LARGE | 0x02000220 | 任務棧大小設置過大 | 減少任務棧大小 |
32 | LOS_ERRNO_TSK_SUSPEND_SWTMR_NOT_ALLOWED | 0x02000221 | 不容許掛起軟件定時器任務 | 檢查任務ID, 不要試圖掛起軟件定時器任務 |
錯誤碼定義:錯誤碼是一個32位的存儲單元, 31~24位表示錯誤等級, 23~16位表示錯誤碼標誌, 15~8位表明錯誤碼所屬模塊, 7~0位表示錯誤碼序號,以下
#define LOS_ERRNO_OS_NORMAL(MID,ERRNO) \ (LOS_ERRTYPE_NORMAL | LOS_ERRNO_OS_ID | ((UINT32)(MID) << 8) | (ERRNO)) LOS_ERRTYPE_NORMAL :Define the error level as critical LOS_ERRNO_OS_ID :OS error code flag. MID:OS_MOUDLE_ID ERRNO:error ID number
例如:
LOS_ERRNO_TSK_NO_MEMORY LOS_ERRNO_OS_FATAL(LOS_MOD_TSK, 0x00)
4.6 平臺差別性
無
4.7 編程實例
4.7.1 實例描述
下面的示例介紹任務的基本操做方法,包含任務建立、任務延時、任務鎖與解鎖調度、掛起和恢復、查詢當前任務PID、根據PID查詢任務信息等操做,闡述任務優先級調度的機制以及各接口的應用。
- 建立了2個任務:TaskHi和TaskLo。
- TaskHi爲高優先級任務。
- TaskLo爲低優先級任務。
4.7.2 編程示例
UINT32 g_uwTskLoID; UINT32 g_uwTskHiID; #define TSK_PRIOR_HI 4 #define TSK_PRIOR_LO 5 UINT32 Example_TaskHi() { UINT32 uwRet; UINT32 uwCurrentID; TSK_INFO_S stTaskInfo; printf("Enter TaskHi Handler.\r\n"); /*延時2個Tick,延時後該任務會掛起,執行剩餘任務中最高優先級的任務(g_uwTskLoID任務)*/ uwRet = LOS_TaskDelay(2); if (uwRet != LOS_OK) { printf("Delay Task Failed.\r\n"); return LOS_NOK; } /*2個Tick時間到了後,該任務恢復,繼續執行*/ printf("TaskHi LOS_TaskDelay Done.\r\n"); /*掛起自身任務*/ uwRet = LOS_TaskSuspend(g_uwTskHiID); if (uwRet != LOS_OK) { printf("Suspend TaskHi Failed.\r\n"); return LOS_NOK; } printf("TaskHi LOS_TaskResume Success.\r\n"); } /*低優先級任務入口函數*/ UINT32 Example_TaskLo() { UINT32 uwRet; UINT32 uwCurrentID; TSK_INFO_S stTaskInfo; printf("Enter TaskLo Handler.\r\n"); /*延時2個Tick,延時後該任務會掛起,執行剩餘任務中就高優先級的任務(背景任務)*/ uwRet = LOS_TaskDelay(2); if (uwRet != LOS_OK) { printf("Delay TaskLo Failed.\r\n"); return LOS_NOK; } printf("TaskHi LOS_TaskSuspend Success.\r\n"); /*恢復被掛起的任務g_uwTskHiID*/ uwRet = LOS_TaskResume(g_uwTskHiID); if (uwRet != LOS_OK) { printf("Resume TaskHi Failed.\r\n"); return LOS_NOK; } printf("TaskHi LOS_TaskDelete Success.\r\n"); } /*任務測試入口函數,在裏面建立優先級不同的兩個任務*/ UINT32 Example_TskCaseEntry(VOID) { UINT32 uwRet; TSK_INIT_PARAM_S stInitParam; /*鎖任務調度*/ LOS_TaskLock(); printf("LOS_TaskLock() Success!\r\n"); stInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_TaskHi; stInitParam.usTaskPrio = TSK_PRIOR_HI; stInitParam.pcName = "HIGH_NAME"; stInitParam.uwStackSize = 0x400; stInitParam.uwResved = LOS_TASK_STATUS_DETACHED; /*建立高優先級任務,因爲鎖任務調度,任務建立成功後不會立刻執行*/ uwRet = LOS_TaskCreate(&g_uwTskHiID, &stInitParam); if (uwRet != LOS_OK) { LOS_TaskUnlock(); printf("Example_TaskHi create Failed!\r\n"); return LOS_NOK; } printf("Example_TaskHi create Success!\r\n"); stInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_TaskLo; stInitParam.usTaskPrio = TSK_PRIOR_LO; stInitParam.pcName = "LOW_NAME"; stInitParam.uwStackSize = 0x400; stInitParam.uwResved = LOS_TASK_STATUS_DETACHED; /*建立低優先級任務,因爲鎖任務調度,任務建立成功後不會立刻執行*/ uwRet = LOS_TaskCreate(&g_uwTskLoID, &stInitParam); if (uwRet != LOS_OK) { LOS_TaskUnlock(); printf("Example_TaskLo create Failed!\r\n"); return LOS_NOK; } printf("Example_TaskLo create Success!\r\n"); /*解鎖任務調度,此時會發生任務調度,執行就緒列表中最高優先級任務*/ LOS_TaskUnlock(); while(1){}; return LOS_OK; }
4.7.3 結果驗證
編譯運行獲得的結果爲: