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 開發流程

以創建任務為例,講解開發流程。

  1. 在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任務監測模塊裁剪開關,可選擇是否打開。

  1. 鎖任務LOS_TaskLock,鎖住任務,防止高優先級任務調度。
  2. 創建任務LOS_TaskCreate。
  3. 解鎖任務LOS_TaskUnlock,讓任務按照優先級進行調度。
  4. 延時任務LOS_TaskDelay,任務延時等待。
  5. 掛起指定的任務LOS_TaskSuspend,任務掛起等待恢復操作。
  6. 恢復掛起的任務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查詢任務信息等操作,闡述任務優先級調度的機制以及各接口的應用。

  1. 創建了2個任務:TaskHi和TaskLo。
  2. TaskHi為高優先級任務。
  3. 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 結果驗證

編譯運行得到的結果為:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM