鴻蒙內(nèi)核M核源碼分析系列四 數(shù)據(jù)結(jié)構(gòu)-任務(wù)排序鏈表

      網(wǎng)友投稿 540 2025-04-01

      鴻蒙輕內(nèi)核M核源碼分析系列四 數(shù)據(jù)結(jié)構(gòu)-任務(wù)排序鏈表


      在鴻蒙輕內(nèi)核源碼分析系列一和系列二,我們分析了雙向循環(huán)鏈表、優(yōu)先級(jí)就緒隊(duì)列的源碼。本文會(huì)繼續(xù)給讀者介紹鴻蒙輕內(nèi)核源碼中重要的數(shù)據(jù)結(jié)構(gòu):任務(wù)排序鏈表TaskSortLinkAttr。鴻蒙輕內(nèi)核的任務(wù)排序鏈表,用于任務(wù)延遲到期/超時(shí)喚醒等業(yè)務(wù)場(chǎng)景,是一個(gè)非常重要、非常基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)。本文中所涉及的源碼,以O(shè)penHarmony LiteOS-M內(nèi)核為例,均可以在開(kāi)源站點(diǎn)https://gitee.com/openharmony/kernel_liteos_m 獲取。

      1 任務(wù)排序鏈表

      我們先看下任務(wù)排序鏈接的數(shù)據(jù)結(jié)構(gòu)。任務(wù)排序鏈表是一個(gè)環(huán)狀的雙向鏈表數(shù)組,任務(wù)排序鏈表屬性結(jié)構(gòu)體TaskSortLinkAttr作為雙向鏈表的頭結(jié)點(diǎn),指向雙向鏈表數(shù)組的第一個(gè)元素,還維護(hù)游標(biāo)信息,記錄當(dāng)前的位置信息。我們先看下排序鏈表屬性的結(jié)構(gòu)體的定義。

      1.1 任務(wù)排序鏈表屬性結(jié)構(gòu)體定義

      在kernel\include\los_task.h頭文件中定義了排序鏈表屬性的結(jié)構(gòu)體TaskSortLinkAttr。該結(jié)構(gòu)體定義了排序鏈表的頭節(jié)點(diǎn)LOS_DL_LIST *sortLink,游標(biāo)UINT16 cursor,還有一個(gè)保留字段,暫時(shí)沒(méi)有使用。

      源碼如下:

      typedef struct { LOS_DL_LIST *sortLink; UINT16 cursor; UINT16 reserved; } TaskSortLinkAttr;

      在文件kernel\src\los_task.c中定義了排序鏈表屬性結(jié)構(gòu)體TaskSortLinkAttr類(lèi)型的全局變量g_taskSortLink,該全局變量的成員變量sortLink作為排序鏈表的頭結(jié)點(diǎn),指向一個(gè)長(zhǎng)度為32的環(huán)狀的雙向鏈表數(shù)組,成員變量cursor作為游標(biāo)記錄環(huán)狀數(shù)組的當(dāng)前游標(biāo)位置。源代碼如下。

      LITE_OS_SEC_BSS TaskSortLinkAttr g_taskSortLink;

      我們使用示意圖來(lái)講述一下。任務(wù)排序鏈表是環(huán)狀雙向鏈表數(shù)組,長(zhǎng)度為32,每一個(gè)元素是一個(gè)雙向鏈表,掛載任務(wù)LosTaskCB的鏈表節(jié)點(diǎn)timerList。任務(wù)LosTaskCB的成員變量idxRollNum記錄數(shù)組的索引和滾動(dòng)數(shù)。全局變量g_taskSortLink的成員變量cursor記錄當(dāng)前游標(biāo)位置,每過(guò)一個(gè)Tick,游標(biāo)指向下一個(gè)位置,轉(zhuǎn)一輪需要32 ticks。當(dāng)運(yùn)行到的數(shù)組位置,雙向鏈表不為空,則把第一個(gè)節(jié)點(diǎn)維護(hù)的滾動(dòng)數(shù)減1。這樣的數(shù)據(jù)結(jié)構(gòu)類(lèi)似鐘表表盤(pán),也稱(chēng)為時(shí)間輪。

      我們舉個(gè)例子來(lái)說(shuō)明,基于時(shí)間輪實(shí)現(xiàn)的任務(wù)排序鏈表是如何管理任務(wù)延遲超時(shí)的。假如當(dāng)前游標(biāo)cursor為1,當(dāng)一個(gè)任務(wù)需要延時(shí)72 ticks,72=2*32+8,表示排序索引sortIndex為8,滾動(dòng)數(shù)rollNum為2。會(huì)把任務(wù)插入數(shù)組索引為sortIndex+cursor=9的雙向鏈表位置,索要9處的雙向鏈表維護(hù)節(jié)點(diǎn)的滾動(dòng)為2。隨著Tick時(shí)間的進(jìn)行,從當(dāng)前游標(biāo)位置運(yùn)行到數(shù)組索引位置9,歷時(shí)8 ticks。運(yùn)行到9時(shí),如果滾動(dòng)數(shù)大于0,則把滾動(dòng)數(shù)減1。等再運(yùn)行2輪,共需要72 ticks,任務(wù)就會(huì)延遲到期,可以從排序鏈表移除。每個(gè)數(shù)組元素對(duì)應(yīng)的雙向鏈表的第一個(gè)鏈表節(jié)點(diǎn)的滾動(dòng)數(shù)表示需要轉(zhuǎn)多少輪,節(jié)點(diǎn)任務(wù)才到期。第二個(gè)鏈表節(jié)點(diǎn)的滾動(dòng)數(shù)需要加上第一個(gè)節(jié)點(diǎn)的滾動(dòng)數(shù),表示第二個(gè)節(jié)點(diǎn)需要轉(zhuǎn)的輪數(shù)。依次類(lèi)推。

      示意圖如下:

      1.2 任務(wù)排序鏈表宏定義

      在OS_TSK_SORTLINK_LEN頭文件中定義了一些和任務(wù)排序鏈表相關(guān)的宏定義。延遲任務(wù)雙向鏈表數(shù)組的長(zhǎng)度定義為32,高階bit位位數(shù)為5,低階bit位位數(shù)為27。對(duì)于任務(wù)的超時(shí)時(shí)間,取其高27位作為滾動(dòng)數(shù),低5位作為數(shù)組索引。

      源碼如下:

      /** * 延遲任務(wù)雙向鏈表數(shù)組的數(shù)量(桶的數(shù)量):32 */ #define OS_TSK_SORTLINK_LEN 32 /** * 高階bit位數(shù)目:5 */ #define OS_TSK_HIGH_BITS 5U /** * 低階bit位數(shù)目:27 */ #define OS_TSK_LOW_BITS (32U - OS_TSK_HIGH_BITS) /** * 滾動(dòng)數(shù)最大值:0xFFFF FFDF,1111 0111 1111 1111 1111 1111 1101 1111 */ #define OS_TSK_MAX_ROLLNUM (0xFFFFFFFFU - OS_TSK_SORTLINK_LEN) /** * 任務(wù)延遲時(shí)間數(shù)的位寬:5 */ #define OS_TSK_SORTLINK_LOGLEN 5 /** * 延遲任務(wù)的桶編號(hào)的掩碼:31、0001 1111 */ #define OS_TSK_SORTLINK_MASK (OS_TSK_SORTLINK_LEN - 1U) /** * 滾動(dòng)數(shù)的高階掩碼:1111 1000 0000 0000 0000 0000 0000 0000 */ #define OS_TSK_HIGH_BITS_MASK (OS_TSK_SORTLINK_MASK << OS_TSK_LOW_BITS) /** * 滾動(dòng)數(shù)的低階掩碼:0000 0111 1111 1111 1111 1111 1111 1111 */ #define OS_TSK_LOW_BITS_MASK (~OS_TSK_HIGH_BITS_MASK)

      2 任務(wù)排序鏈表操作

      我們分析下任務(wù)排序鏈表的操作,包含初始化,插入,刪除,滾動(dòng)數(shù)更新,獲取下一個(gè)到期時(shí)間等。

      2.1 初始化排序鏈表

      在系系統(tǒng)內(nèi)核初始化啟動(dòng)階段,在函數(shù)UINT32 OsTaskInit(VOID)中初始化任務(wù)排序鏈表。該函數(shù)的調(diào)用關(guān)系如下,main.c:main() --> kernel\src\los_init.c:LOS_KernelInit() --> kernel\src\los_task.c:OsTaskInit()。

      初始化排序鏈表函數(shù)的源碼如下:

      鴻蒙輕內(nèi)核M核源碼分析系列四 數(shù)據(jù)結(jié)構(gòu)-任務(wù)排序鏈表

      LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID) { UINT32 size; UINT32 index; LOS_DL_LIST *listObject = NULL; ...... ⑴ size = sizeof(LOS_DL_LIST) * OS_TSK_SORTLINK_LEN; listObject = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, size); ⑵ if (listObject == NULL) { (VOID)LOS_MemFree(m_aucSysMem0, g_taskCBArray); return LOS_ERRNO_TSK_NO_MEMORY; } ⑶ (VOID)memset_s((VOID *)listObject, size, 0, size); ⑷ g_taskSortLink.sortLink = listObject; g_taskSortLink.cursor = 0; for (index = 0; index < OS_TSK_SORTLINK_LEN; index++, listObject++) { ⑸ LOS_ListInit(listObject); } return LOS_OK; }

      ⑴處代碼計(jì)算需要申請(qǐng)的雙向鏈表的內(nèi)存大小,OS_TSK_SORTLINK_LEN為32,即需要為32個(gè)雙向鏈表節(jié)點(diǎn)申請(qǐng)內(nèi)存空間。然后申請(qǐng)內(nèi)存,⑵處申請(qǐng)內(nèi)存失敗時(shí)返回相應(yīng)錯(cuò)誤碼。⑶處初始化申請(qǐng)的內(nèi)存區(qū)域?yàn)?等。⑷處把申請(qǐng)的雙向鏈表節(jié)點(diǎn)賦值給g_taskSortLink的鏈表節(jié)點(diǎn).sortLink,作為排序鏈表的頭節(jié)點(diǎn),游標(biāo).cursor初始化為0。然后⑸處的循環(huán),調(diào)用LOS_ListInit()函數(shù)把雙向鏈表數(shù)組每個(gè)元素都初始化為雙向循環(huán)鏈表。

      2.2 插入排序鏈表

      插入排序鏈表的函數(shù)為OsTaskAdd2TimerList()。在任務(wù)等待互斥鎖/信號(hào)量等資源時(shí),都需要調(diào)用該函數(shù)將任務(wù)加入到對(duì)應(yīng)的排序鏈表中。該函數(shù)包含兩個(gè)入?yún)ⅲ谝粋€(gè)參數(shù)LosTaskCB *taskCB用于指定要延遲的任務(wù),第二個(gè)參數(shù)UINT32 timeout指定超時(shí)等待時(shí)間。

      源碼如下:

      LITE_OS_SEC_TEXT VOID OsTaskAdd2TimerList(LosTaskCB *taskCB, UINT32 timeout) { LosTaskCB *taskDelay = NULL; LOS_DL_LIST *listObject = NULL; UINT32 sortIndex; UINT32 rollNum; ⑴ sortIndex = timeout & OS_TSK_SORTLINK_MASK; rollNum = (timeout >> OS_TSK_SORTLINK_LOGLEN); ⑵ (sortIndex > 0) ? 0 : (rollNum--); ⑶ EVALUATE_L(taskCB->idxRollNum, rollNum); ⑷ sortIndex = (sortIndex + g_taskSortLink.cursor); sortIndex = sortIndex & OS_TSK_SORTLINK_MASK; ⑸ EVALUATE_H(taskCB->idxRollNum, sortIndex); ⑹ listObject = g_taskSortLink.sortLink + sortIndex; ⑺ if (listObject->pstNext == listObject) { LOS_ListTailInsert(listObject, &taskCB->timerList); } else { ⑻ taskDelay = LOS_DL_LIST_ENTRY((listObject)->pstNext, LosTaskCB, timerList); do { ⑼ if (UWROLLNUM(taskDelay->idxRollNum) <= UWROLLNUM(taskCB->idxRollNum)) { UWROLLNUMSUB(taskCB->idxRollNum, taskDelay->idxRollNum); } else { ⑽ UWROLLNUMSUB(taskDelay->idxRollNum, taskCB->idxRollNum); break; } ⑾ taskDelay = LOS_DL_LIST_ENTRY(taskDelay->timerList.pstNext, LosTaskCB, timerList); } while (&taskDelay->timerList != (listObject)); ⑿ LOS_ListTailInsert(&taskDelay->timerList, &taskCB->timerList); } }

      ⑴處代碼計(jì)算等待時(shí)間timeout的低5位作為數(shù)組索引,高27位作為滾動(dòng)數(shù)rollNum。這2行代碼數(shù)學(xué)上的意義,就是把等待時(shí)間處于32得到的商作為滾動(dòng)數(shù),余數(shù)作為數(shù)組索引。⑵處代碼,如果余數(shù)為0,可以整除時(shí),滾動(dòng)數(shù)減1。減1設(shè)計(jì)的原因是,在函數(shù)VOID OsTaskScan(VOID)中,每一個(gè)tick到來(lái)時(shí),如果滾動(dòng)數(shù)大于0,滾動(dòng)數(shù)減1,并繼續(xù)滾動(dòng)一圈。后文會(huì)分析該函數(shù)VOID OsTaskScan(VOID)。

      ⑶處代碼把滾動(dòng)數(shù)賦值給任務(wù)taskCB->idxRollNum的低27位。⑷處把數(shù)組索引加上游標(biāo),然后執(zhí)行⑸賦值給任務(wù)taskCB->idxRollNum的高5位。⑹根據(jù)數(shù)組索引獲取雙向鏈表頭結(jié)點(diǎn),⑺如果此處雙向鏈表為空,直接插入鏈表里。如果鏈表不為空,執(zhí)行⑻獲取第一個(gè)鏈表節(jié)點(diǎn)對(duì)應(yīng)的任務(wù)taskDelay,然后遍歷循環(huán)雙向鏈表,把任務(wù)插入到合適的位置。⑼處如果待插入任務(wù)taskCB的滾動(dòng)數(shù)大于等于當(dāng)前鏈表節(jié)點(diǎn)對(duì)應(yīng)任務(wù)的滾動(dòng)數(shù),則從待插入任務(wù)taskCB的滾動(dòng)數(shù)中減去當(dāng)前鏈表節(jié)點(diǎn)對(duì)應(yīng)任務(wù)的滾動(dòng)數(shù),然后執(zhí)行⑾獲取下一個(gè)節(jié)點(diǎn)繼續(xù)遍歷。⑽處如果待插入任務(wù)taskCB的滾動(dòng)數(shù)小于當(dāng)前鏈表節(jié)點(diǎn)對(duì)應(yīng)任務(wù)的滾動(dòng)數(shù),則從當(dāng)前鏈表節(jié)點(diǎn)對(duì)應(yīng)任務(wù)的滾動(dòng)數(shù)中減去待插入任務(wù)taskCB的滾動(dòng)數(shù),然后跳出循環(huán)。執(zhí)行⑿,完成任務(wù)插入。插入過(guò)程,可以結(jié)合上文的示意圖進(jìn)行理解。

      2.3 從排序鏈表中刪除

      從排序鏈表中刪除的函數(shù)為VOID OsTimerListDelete(LosTaskCB *taskCB)。在任務(wù)恢復(fù)/刪除等場(chǎng)景中,需要調(diào)用該函數(shù)將任務(wù)從任務(wù)排序鏈表中刪除。該函數(shù)包含一個(gè)參數(shù)LosTaskCB *taskCB,用于指定要從排序鏈表中刪除的任務(wù)。

      源碼如下:

      LITE_OS_SEC_TEXT VOID OsTimerListDelete(LosTaskCB *taskCB) { LOS_DL_LIST *listObject = NULL; LosTaskCB *nextTask = NULL; UINT32 sortIndex; ⑴ sortIndex = UWSORTINDEX(taskCB->idxRollNum); ⑵ listObject = g_taskSortLink.sortLink + sortIndex; ⑶ if (listObject != taskCB->timerList.pstNext) { ⑷ nextTask = LOS_DL_LIST_ENTRY(taskCB->timerList.pstNext, LosTaskCB, timerList); UWROLLNUMADD(nextTask->idxRollNum, taskCB->idxRollNum); } ⑸ LOS_ListDelete(&taskCB->timerList); }

      ⑴處代碼獲取待從排序鏈表中刪除的任務(wù)對(duì)應(yīng)的數(shù)字索引。⑵處代碼獲取排序鏈表的頭節(jié)點(diǎn)listObject。⑶處代碼判斷待刪除節(jié)點(diǎn)是否是最后一個(gè)節(jié)點(diǎn),如果不是最后一個(gè)節(jié)點(diǎn),執(zhí)行執(zhí)行⑷處代碼獲取待刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的任務(wù)nextTask,在下一個(gè)節(jié)點(diǎn)的滾動(dòng)數(shù)中增加待刪除節(jié)點(diǎn)的滾動(dòng)數(shù),然后執(zhí)行⑸處代碼執(zhí)行刪除操作。如果是最后一個(gè)節(jié)點(diǎn),直接執(zhí)行⑸處代碼刪除該節(jié)點(diǎn)即可。

      2.4 獲取下一個(gè)超時(shí)到期時(shí)間

      獲取下一個(gè)超時(shí)到期時(shí)間的函數(shù)為OsTaskNextSwitchTimeGet(),我們分析下其代碼。

      源碼如下:

      UINT32 OsTaskNextSwitchTimeGet(VOID) { LosTaskCB *taskCB = NULL; UINT32 taskSortLinkTick = LOS_WAIT_FOREVER; LOS_DL_LIST *listObject = NULL; UINT32 tempTicks; UINT32 index; ⑴ for (index = 0; index < OS_TSK_SORTLINK_LEN; index++) { ⑵ listObject = g_taskSortLink.sortLink + ((g_taskSortLink.cursor + index) % OS_TSK_SORTLINK_LEN); ⑶ if (!LOS_ListEmpty(listObject)) { ⑷ taskCB = LOS_DL_LIST_ENTRY((listObject)->pstNext, LosTaskCB, timerList); ⑸ tempTicks = (index == 0) ? OS_TSK_SORTLINK_LEN : index; ⑹ tempTicks += (UINT32)(UWROLLNUM((UINT32)taskCB->idxRollNum) * OS_TSK_SORTLINK_LEN); ⑺ if (taskSortLinkTick > tempTicks) { taskSortLinkTick = tempTicks; } } } return taskSortLinkTick; }

      ⑴處代碼循環(huán)遍歷雙向鏈表數(shù)組,⑵處代碼從當(dāng)前游標(biāo)位置開(kāi)始獲取排序鏈表的頭節(jié)點(diǎn)listObject。⑶處代碼判斷排序鏈表是否為空,如果排序鏈表為空,則繼續(xù)遍歷下一個(gè)數(shù)組。如果鏈表不為空,⑷處代碼獲取排序鏈表的第一個(gè)鏈表節(jié)點(diǎn)對(duì)應(yīng)的任務(wù)。⑸處如果遍歷的數(shù)字索引為0,tick數(shù)目使用32,否則使用具體的數(shù)字索引。⑹處獲取任務(wù)的滾動(dòng)數(shù),計(jì)算出需要的等待時(shí)間,加上⑸處計(jì)算出的不足滾動(dòng)一圈的時(shí)間。⑺處計(jì)算出需要等待的最小時(shí)間,即下一個(gè)最快到期的時(shí)間。

      3 排序鏈表和Tick時(shí)間的關(guān)系

      任務(wù)加入到排序鏈表后,時(shí)間一個(gè)tick一個(gè)tick的逝去,排序鏈表中的滾動(dòng)數(shù)該如何更新呢?

      時(shí)間每走過(guò)一個(gè)tick,系統(tǒng)就會(huì)調(diào)用Tick中斷的處理函數(shù)OsTickHandler(),該函數(shù)在kernel\src\los_tick.c文件中實(shí)現(xiàn)。下面是該函數(shù)的代碼片段,⑴處代碼分別任務(wù)的超時(shí)到期情況。

      LITE_OS_SEC_TEXT VOID OsTickHandler(VOID) { #if (LOSCFG_BASE_CORE_TICK_HW_TIME == 1) platform_tick_handler(); #endif g_ullTickCount++; #if (LOSCFG_BASE_CORE_TIMESLICE == 1) OsTimesliceCheck(); #endif ⑴ OsTaskScan(); // task timeout scan #if (LOSCFG_BASE_CORE_SWTMR == 1) (VOID)OsSwtmrScan(); #endif }

      詳細(xì)分析下函數(shù)OsTaskScan(),來(lái)了解排序鏈表和tick時(shí)間的關(guān)系。函數(shù)在kernel\base\los_task.c文件中實(shí)現(xiàn),代碼片段如下:

      LITE_OS_SEC_TEXT VOID OsTaskScan(VOID) { LosTaskCB *taskCB = NULL; BOOL needSchedule = FALSE; LOS_DL_LIST *listObject = NULL; UINT16 tempStatus; UINTPTR intSave; intSave = LOS_IntLock(); ⑴ g_taskSortLink.cursor = (g_taskSortLink.cursor + 1) % OS_TSK_SORTLINK_LEN; listObject = g_taskSortLink.sortLink + g_taskSortLink.cursor; ⑵ if (listObject->pstNext == listObject) { LOS_IntRestore(intSave); return; } ⑶ for (taskCB = LOS_DL_LIST_ENTRY((listObject)->pstNext, LosTaskCB, timerList); &taskCB->timerList != (listObject);) { tempStatus = taskCB->taskStatus; ⑷ if (UWROLLNUM(taskCB->idxRollNum) > 0) { UWROLLNUMDEC(taskCB->idxRollNum); break; } ⑸ LOS_ListDelete(&taskCB->timerList); ⑹ if (tempStatus & OS_TASK_STATUS_PEND) { taskCB->taskStatus &= ~(OS_TASK_STATUS_PEND); LOS_ListDelete(&taskCB->pendList); taskCB->taskSem = NULL; taskCB->taskMux = NULL; } ⑺ else if (tempStatus & OS_TASK_STATUS_EVENT) { taskCB->taskStatus &= ~(OS_TASK_STATUS_EVENT); } ⑻ else if (tempStatus & OS_TASK_STATUS_PEND_QUEUE) { LOS_ListDelete(&taskCB->pendList); taskCB->taskStatus &= ~(OS_TASK_STATUS_PEND_QUEUE); } else { taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY); } ⑼ if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) { taskCB->taskStatus |= OS_TASK_STATUS_READY; OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOREADYSTATE, taskCB); OsPriqueueEnqueue(&taskCB->pendList, taskCB->priority); needSchedule = TRUE; } if (listObject->pstNext == listObject) { break; } taskCB = LOS_DL_LIST_ENTRY(listObject->pstNext, LosTaskCB, timerList); } LOS_IntRestore(intSave); ⑽ if (needSchedule) { LOS_Schedule(); } }

      ⑴處代碼更新全局變量g_taskSortLink的游標(biāo),指向雙向鏈表數(shù)組下一個(gè)位置,然后獲取該位置的雙向鏈表頭結(jié)點(diǎn)listObject。⑵如果鏈表為空,則返回。如果雙向鏈表不為空,則執(zhí)行⑶循環(huán)遍歷每一個(gè)鏈表節(jié)點(diǎn)。⑷處如果鏈表節(jié)點(diǎn)的滾動(dòng)數(shù)大于0,則滾動(dòng)數(shù)減1,說(shuō)明任務(wù)還需要繼續(xù)等待一輪。如果鏈表節(jié)點(diǎn)的滾動(dòng)數(shù)等于0,說(shuō)明任務(wù)超時(shí)到期,執(zhí)行⑸從排序鏈表中刪除。接下來(lái)需要根據(jù)任務(wù)狀態(tài)分別處理,⑹處如果代碼是阻塞狀態(tài),取消阻塞狀態(tài),并從阻塞鏈表中刪除。⑺處如果任務(wù)阻塞在事件中,取消阻塞狀態(tài)。⑻如果任務(wù)阻塞在隊(duì)列,從阻塞鏈表中刪除,取消阻塞狀態(tài),如果不是上述狀態(tài),取消延遲狀態(tài)OS_TASK_STATUS_DELAY。⑼處如果代碼是掛起狀態(tài),設(shè)置任務(wù)為就緒狀態(tài),加入任務(wù)就緒隊(duì)列,設(shè)置需要重新調(diào)度標(biāo)記。⑽如果設(shè)置需要重新調(diào)度,調(diào)用調(diào)度函數(shù)觸發(fā)任務(wù)調(diào)度。

      小結(jié)

      掌握鴻蒙輕內(nèi)核的排序鏈表TaskSortLinkAttr這一重要的數(shù)據(jù)結(jié)構(gòu),會(huì)給進(jìn)一步學(xué)習(xí)、分析鴻蒙輕內(nèi)核源代碼打下了基礎(chǔ),讓后續(xù)的學(xué)習(xí)更加容易。后續(xù)也會(huì)陸續(xù)推出更多的分享文章,敬請(qǐng)期待,也歡迎大家分享學(xué)習(xí)、使用鴻蒙輕內(nèi)核的心得,有任何問(wèn)題、建議,都可以留言給我們: https://gitee.com/openharmony/kernel_liteos_m/issues 。為了更容易找到鴻蒙輕內(nèi)核代碼倉(cāng),建議訪(fǎng)問(wèn) https://gitee.com/openharmony/kernel_liteos_m ,關(guān)注Watch、Star、并Fork到自己賬戶(hù)下,謝謝。

      IoT 任務(wù)調(diào)度 數(shù)據(jù)結(jié)構(gòu) 輕量級(jí)操作系統(tǒng) LiteOS

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:如何快速選擇工作表中的大量單元格?
      下一篇:07版excel表格如何制作(2007版的excel表格制作)
      相關(guān)文章
      亚洲AV无码久久精品色欲| www国产亚洲精品久久久| 亚洲综合熟女久久久30p| 国产午夜亚洲精品不卡电影| 久久精品国产亚洲αv忘忧草| 亚洲国产成人va在线观看网址| 亚洲高清视频在线播放| 久久久亚洲AV波多野结衣| 亚洲欧洲日产国码久在线观看| 久久精品国产亚洲av成人| 亚洲av无码一区二区三区网站| 亚洲成av人在线视| 亚洲国产天堂久久综合网站| 亚洲AV无码久久精品蜜桃| 亚洲va国产va天堂va久久| 亚洲熟妇av一区二区三区漫画| 亚洲一区二区三区香蕉| 伊人久久亚洲综合| 亚洲熟妇无码乱子AV电影| 国产亚洲精品一品区99热| 国产成人亚洲综合无码精品 | 国产亚洲精品成人久久网站| 亚洲日韩国产欧美一区二区三区| 伊人久久五月丁香综合中文亚洲| 亚洲日韩AV一区二区三区中文| 亚洲av成人中文无码专区| 一本久久综合亚洲鲁鲁五月天| 亚洲日本韩国在线| 亚洲乱码一区二区三区在线观看| 亚洲成色www久久网站夜月| 亚洲精品高清国产一久久| 久久久亚洲AV波多野结衣| 99999久久久久久亚洲| 亚洲欧洲无码AV不卡在线| 亚洲AV无码一区二三区| 亚洲中文字幕无码日韩| 亚洲一本综合久久| 亚洲一级毛片免观看| 亚洲av成人一区二区三区在线播放| 日韩亚洲人成网站| 国产AV无码专区亚洲AV毛网站|