任務 1 基本概念 從系統的角度看,任務是競爭系統資源的最小運行單元。任務可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它任務運行。 Huawei LiteOS的任務模塊可以給用戶提供多個任務,實現了任務之間的切換和通信,幫助用戶管理業務程式流程。這樣用戶可以將更多的精力投入到業務功能的實 ...
任務
1 基本概念
從系統的角度看,任務是競爭系統資源的最小運行單元。任務可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它任務運行。
Huawei LiteOS的任務模塊可以給用戶提供多個任務,實現了任務之間的切換和通信,幫助用戶管理業務程式流程。這樣用戶可以將更多的精力投入到業務功能的實現中。
Huawei LiteOS是一個支持多任務的操作系統。在Huawei LiteOS中,一個任務表示一個線程。
Huawei LiteOS中的任務是搶占式調度機制,同時支持時間片輪轉調度方式。
高優先順序的任務可打斷低優先順序任務,低優先順序任務必須在高優先順序任務阻塞或結束後才能得到調度。
Huawei LiteOS的任務一共有32個優先順序(0-31),最高優先順序為0,最低優先順序為31。
2 任務相關概念
2.1 任務狀態
Huawei LiteOS系統中的每一任務都有多種運行狀態。系統初始化完成後,創建的任務就可以在系統中競爭一定的資源,由內核進行調度。
任務狀態通常分為以下四種:
- 就緒(Ready):該任務在就緒列表中,只等待CPU。
- 運行(Running):該任務正在執行。
- 阻塞(Blocked):該任務不在就緒列表中。包含任務被掛起、任務被延時、任務正在等待信號量、讀寫隊列或者等待讀寫事件等。
- 退出態(Dead):該任務運行結束,等待系統回收資源。
圖 3-1 任務狀態示意圖
- 就緒態-》運行態
任務創建後進入就緒態,發生任務切換時,就緒列表中最高優先順序的任務被執行,從而進入運行態,但此刻該任務依舊在就緒列表中。
- 運行態→阻塞態:
正在運行的任務發生阻塞(掛起、延時、讀信號量等待)時,該任務會從就緒列表中刪除,任務狀態由運行態變成阻塞態,然後發生任務切換,運行就緒列表中剩餘最高優先順序任務。
- 阻塞態→就緒態(阻塞態→運行態):
阻塞的任務被恢復後(任務恢復、延時時間超時、讀信號量超時或讀到信號量等),此時被恢復的任務會被加入就緒列表,從而由阻塞態變成就緒態;此時如果被恢復任務的優先順序高於正在運行任務的優先順序,則會發生任務切換,將該任務由就緒態變成運行態。
- 阻塞態→退出態
阻塞的任務調用刪除介面,任務狀態由阻塞態變為退出態。
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 結果驗證
編譯運行得到的結果為: