日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

任务延时队列

發(fā)布時間:2025/4/5 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 任务延时队列 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 1 任務延時隊列
      • 1.1 現(xiàn)有問題
      • 1.2 延時隊列設計
      • 1.3 設計實現(xiàn)

1 任務延時隊列

1.1 現(xiàn)有問題

現(xiàn)有問題:

  • 每次時鐘節(jié)拍中斷都需要掃描所有任務,比較耗時。
  • 不易支持多個任務具有相同優(yōu)先級。

    我們需要更加快速、簡單的結(jié)構(gòu),我們可以設計一個延時隊列。將所有需要延時的任務單獨放置在一個隊列中,每次發(fā)生系統(tǒng)時鐘節(jié)拍時,只需要掃描該隊列。可以有兩種實現(xiàn)方式:

方式一:獨立保存延時時間。

方式二:遞增的延時隊列。

1.2 延時隊列設計

對于上述兩種延時隊列的設計方式,比較如下:

  • 方式一插入延遲任務比較簡單,快速;掃描整個隊列教簡單,但較慢。
  • 方式二插入延時任務比較復雜,較慢;掃描整個隊列較復雜,但較快。

我們采用方式一進行設計。

1.3 設計實現(xiàn)

添加延時隊列:

延時隊列的插入:

延時隊列的刪除:

時鐘節(jié)拍掃描延時隊列:

實現(xiàn)代碼如下:

/*************************************** Copyright (c)****************************************************** ** File name : main.c ** Latest modified Date : 2016-06-01 ** Latest Version : 0.1 ** Descriptions : 主文件,包含應用代碼 ** **-------------------------------------------------------------------------------------------------------- ** Created by : 01課堂 lishutong ** Created date : 2016-06-01 ** Version : 1.0 ** Descriptions : The original version ** **-------------------------------------------------------------------------------------------------------- ** Copyright : 版權(quán)所有,禁止用于商業(yè)用途 ** Author Blog : http://ilishutong.com **********************************************************************************************************/ #include "tinyOS.h" #include "ARMCM3.h"// 當前任務:記錄當前是哪個任務正在運行 tTask * currentTask;// 下一個將即運行的任務:在進行任務切換前,先設置好該值,然后任務切換過程中會從中讀取下一任務信息 tTask * nextTask;// 空閑任務 tTask * idleTask;// 任務優(yōu)先級的標記位置結(jié)構(gòu) tBitmap taskPrioBitmap;// 所有任務的指針數(shù)組:簡單起見,只使用兩個任務 tTask * taskTable[TINYOS_PRO_COUNT];// 調(diào)度鎖計數(shù)器 uint8_t schedLockCount;// 延時隊列 tList tTaskDelayedList;/********************************************************************************************************** ** Function name : tTaskInit ** Descriptions : 初始化任務結(jié)構(gòu) ** parameters : task 要初始化的任務結(jié)構(gòu) ** parameters : entry 任務的入口函數(shù) ** parameters : param 傳遞給任務的運行參數(shù) ** Returned value : 無 ***********************************************************************************************************/ void tTaskInit (tTask * task, void (*entry)(void *), void *param, uint32_t prio, uint32_t * stack) {// 為了簡化代碼,tinyOS無論是在啟動時切換至第一個任務,還是在運行過程中在不同間任務切換// 所執(zhí)行的操作都是先保存當前任務的運行環(huán)境參數(shù)(CPU寄存器值)的堆棧中(如果已經(jīng)運行運行起來的話),然后再// 取出從下一個任務的堆棧中取出之前的運行環(huán)境參數(shù),然后恢復到CPU寄存器// 對于切換至之前從沒有運行過的任務,我們?yōu)樗渲靡粋€“虛假的”保存現(xiàn)場,然后使用該現(xiàn)場恢復。// 注意以下兩點:// 1、不需要用到的寄存器,直接填了寄存器號,方便在IDE調(diào)試時查看效果;// 2、順序不能變,要結(jié)合PendSV_Handler以及CPU對異常的處理流程來理解*(--stack) = (unsigned long)(1<<24); // XPSR, 設置了Thumb模式,恢復到Thumb狀態(tài)而非ARM狀態(tài)運行*(--stack) = (unsigned long)entry; // 程序的入口地址*(--stack) = (unsigned long)0x14; // R14(LR), 任務不會通過return xxx結(jié)束自己,所以未用*(--stack) = (unsigned long)0x12; // R12, 未用*(--stack) = (unsigned long)0x3; // R3, 未用*(--stack) = (unsigned long)0x2; // R2, 未用*(--stack) = (unsigned long)0x1; // R1, 未用*(--stack) = (unsigned long)param; // R0 = param, 傳給任務的入口函數(shù)*(--stack) = (unsigned long)0x11; // R11, 未用*(--stack) = (unsigned long)0x10; // R10, 未用*(--stack) = (unsigned long)0x9; // R9, 未用*(--stack) = (unsigned long)0x8; // R8, 未用*(--stack) = (unsigned long)0x7; // R7, 未用*(--stack) = (unsigned long)0x6; // R6, 未用*(--stack) = (unsigned long)0x5; // R5, 未用*(--stack) = (unsigned long)0x4; // R4, 未用task->stack = stack; // 保存最終的值task->delayTicks = 0;task->prio = prio; // 設置任務的優(yōu)先級task->state = TINYOS_TASK_STATE_RDY; // 設置任務為就緒狀態(tài)tNodeInit(&(task->delayNode)); // 初始化延時結(jié)點taskTable[prio] = task; // 填入任務優(yōu)先級表tBitmapSet(&taskPrioBitmap, prio); // 標記優(yōu)先級位置中的相應位 }/********************************************************************************************************** ** Function name : tTaskHighestReady ** Descriptions : 獲取當前最高優(yōu)先級且可運行的任務 ** parameters : 無 ** Returned value : 優(yōu)先級最高的且可運行的任務 ***********************************************************************************************************/ tTask * tTaskHighestReady (void) {uint32_t highestPrio = tBitmapGetFirstSet(&taskPrioBitmap);return taskTable[highestPrio]; }/********************************************************************************************************** ** Function name : 初始化調(diào)度器 ** Descriptions : 無 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSchedInit (void) {schedLockCount = 0; }/********************************************************************************************************** ** Function name : tTaskSchedDisable ** Descriptions : 禁止任務調(diào)度 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSchedDisable (void) {uint32_t status = tTaskEnterCritical();if (schedLockCount < 255) {schedLockCount++;}tTaskExitCritical(status); }/********************************************************************************************************** ** Function name : tTaskSchedEnable ** Descriptions : 允許任務調(diào)度 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSchedEnable (void) {uint32_t status = tTaskEnterCritical();if (schedLockCount > 0) {if (--schedLockCount == 0) {tTaskSched(); }}tTaskExitCritical(status); }/********************************************************************************************************** ** Function name : tTaskSchedRdy ** Descriptions : 將任務設置為就緒狀態(tài) ** input parameters : task 等待設置為就緒狀態(tài)的任務 ** output parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSchedRdy (tTask * task) {taskTable[task->prio] = task;tBitmapSet(&taskPrioBitmap, task->prio); }/************************************************************************************************************ Function name : tSchedulerUnRdyTask ** Descriptions : tTaskSchedUnRdy ** Descriptions : 將任務從就緒列表中移除 ** input parameters : task òaò?3yμ?è????é ** output parameters : None ** Returned value : None ***********************************************************************************************************/ void tTaskSchedUnRdy (tTask * task) {taskTable[task->prio] = (tTask *)0;tBitmapClear(&taskPrioBitmap, task->prio); }/********************************************************************************************************** ** Function name : tTaskSched ** Descriptions : 任務調(diào)度接口。tinyOS通過它來選擇下一個具體的任務,然后切換至該任務運行。 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSched (void) { tTask * tempTask;// 進入臨界區(qū),以保護在整個任務調(diào)度與切換期間,不會因為發(fā)生中斷導致currentTask和nextTask可能更改uint32_t status = tTaskEnterCritical();// 如何調(diào)度器已經(jīng)被上鎖,則不進行調(diào)度,直接退bmif (schedLockCount > 0) {tTaskExitCritical(status);return;}// 找到優(yōu)先級最高的任務。這個任務的優(yōu)先級可能比當前低低// 但是當前任務是因為延時才需要切換,所以必須切換過去,也就是說不能再通過判斷優(yōu)先級來決定是否切換// 只要判斷不是當前任務,就立即切換過去tempTask = tTaskHighestReady();if (tempTask != currentTask) {nextTask = tempTask;tTaskSwitch(); }// 退出臨界區(qū)tTaskExitCritical(status); }/********************************************************************************************************** ** Function name : tTaskDelayedInit ** Descriptions : 初始化任務延時機制 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskDelayedInit (void) {tListInit(&tTaskDelayedList); }/********************************************************************************************************** ** Function name : tTimeTaskWait ** Descriptions : 將任務加入延時隊列中 ** input parameters : task 需要延時的任務 ** ticks 延時的ticks ** output parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTimeTaskWait (tTask * task, uint32_t ticks) {task->delayTicks = ticks;tListAddLast(&tTaskDelayedList, &(task->delayNode)); task->state |= TINYOS_TASK_STATE_DELAYED; }/********************************************************************************************************** ** Function name : tTimeTaskWakeUp ** Descriptions : 將延時的任務從延時隊列中喚醒 ** input parameters : task 需要喚醒的任務 ** output parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTimeTaskWakeUp (tTask * task) {tListRemove(&tTaskDelayedList, &(task->delayNode));task->state &= ~TINYOS_TASK_STATE_DELAYED; }/********************************************************************************************************** ** Function name : tTaskSystemTickHandler ** Descriptions : 系統(tǒng)時鐘節(jié)拍處理。 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void tTaskSystemTickHandler () {tNode * node;// 進入臨界區(qū),以保護在整個任務調(diào)度與切換期間,不會因為發(fā)生中斷導致currentTask和nextTask可能更改uint32_t status = tTaskEnterCritical();// 檢查所有任務的delayTicks數(shù),如果不0的話,減1。for (node = tTaskDelayedList.headNode.nextNode; node != &(tTaskDelayedList.headNode); node = node->nextNode){tTask * task = tNodeParent(node, tTask, delayNode);if (--task->delayTicks == 0) {// 將任務從延時隊列中移除tTimeTaskWakeUp(task);// 將任務恢復到就緒狀態(tài)tTaskSchedRdy(task); }}// 退出臨界區(qū)tTaskExitCritical(status); // 這個過程中可能有任務延時完畢(delayTicks = 0),進行一次調(diào)度。tTaskSched(); }/********************************************************************************************************** ** Function name : tTaskDelay ** Descriptions : 使當前任務進入延時狀態(tài)。 ** parameters : delay 延時多少個ticks ** Returned value : 無 ***********************************************************************************************************/ void tTaskDelay (uint32_t delay) {// 進入臨界區(qū),以保護在整個任務調(diào)度與切換期間,不會因為發(fā)生中斷導致currentTask和nextTask可能更改uint32_t status = tTaskEnterCritical();// 設置延時值,插入延時隊列tTimeTaskWait(currentTask, delay);// 將任務從就緒表中移除tTaskSchedUnRdy(currentTask);// 然后進行任務切換,切換至另一個任務,或者空閑任務// delayTikcs會在時鐘中斷中自動減1.當減至0時,會切換回來繼續(xù)運行。tTaskSched();// 退出臨界區(qū)tTaskExitCritical(status); }/********************************************************************************************************* ** 系統(tǒng)時鐘節(jié)拍定時器System Tick配置 ** 在我們目前的環(huán)境(模擬器)中,系統(tǒng)時鐘節(jié)拍為12MHz ** 請務必按照本教程推薦配置,否則systemTick的值就會有變化,需要查看數(shù)據(jù)手冊才了解 **********************************************************************************************************/ void tSetSysTickPeriod(uint32_t ms) {SysTick->LOAD = ms * SystemCoreClock / 1000 - 1; NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);SysTick->VAL = 0; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk |SysTick_CTRL_ENABLE_Msk; }/********************************************************************************************************** ** Function name : SysTick_Handler ** Descriptions : SystemTick的中斷處理函數(shù)。 ** parameters : 無 ** Returned value : 無 ***********************************************************************************************************/ void SysTick_Handler () {tTaskSystemTickHandler(); }/********************************************************************************************************** ** 應用示例 ** 有兩個任務,分別執(zhí)行task1Entry和task2Entry ** 其中task1Entry的優(yōu)先級更高,只要它不處于延時狀態(tài),那么就運行它 ** task2Entry則只能在task1Entry延時時才能運行 **********************************************************************************************************/ int task1Flag; void task1Entry (void * param) {tSetSysTickPeriod(10);for (;;) {task1Flag = 1;tTaskDelay(1);task1Flag = 0;tTaskDelay(1);} }int task2Flag; void task2Entry (void * param) {for (;;) {task2Flag = 1;tTaskDelay(1);task2Flag = 0;tTaskDelay(1);} }// 任務1和任務2的任務結(jié)構(gòu),以及用于堆棧空間 tTask tTask1; tTask tTask2; tTaskStack task1Env[1024]; tTaskStack task2Env[1024];// 用于空閑任務的任務結(jié)構(gòu)和堆棧空間 tTask tTaskIdle; tTaskStack idleTaskEnv[1024];void idleTaskEntry (void * param) {for (;;){// 空閑任務什么都不做} }int main () {// 優(yōu)先初始化tinyOS的核心功能tTaskSchedInit();// 初始化延時隊列tTaskDelayedInit();// 初始化任務1和任務2結(jié)構(gòu),傳遞運行的起始地址,想要給任意參數(shù),以及運行堆棧空間tTaskInit(&tTask1, task1Entry, (void *)0x11111111, 0, &task1Env[1024]);tTaskInit(&tTask2, task2Entry, (void *)0x22222222, 1, &task2Env[1024]);// 創(chuàng)建空閑任務tTaskInit(&tTaskIdle, idleTaskEntry, (void *)0, TINYOS_PRO_COUNT - 1, &idleTaskEnv[1024]);// 這里,不再指定先運行哪個任務,而是自動查找最高優(yōu)先級的任務運行nextTask = tTaskHighestReady();// 切換到nextTask, 這個函數(shù)永遠不會返回tTaskRunFirst();return 0; }

參考資料:

  • 【李述銅】從0到1自己動手寫嵌入式操作系統(tǒng)
  • 總結(jié)

    以上是生活随笔為你收集整理的任务延时队列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。