任務
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 結果驗證
編譯執行得到的結果為: