首页 > 解决方案 > 从列表 FreeRTOS 定期调度任务

问题描述

我正在使用 FreeRTOS 调度 4 个定期任务的任务集。所有任务都有相同的 10 个时间单位,但它们的发布时间不同。任务 T1、T2、T3、T4 的发布时间分别为 10、3、5、0 个时间单位。所有 4 个任务都存储在链表中gll_t* pTaskList。任务应该运行,例如,t=0 T4 被释放,t=3 T2 被释放,t=5 T3 被释放,t=10 T1 被释放,T4 在 t = 0 被释放后再次执行,依此类推。 ..

但是,我的调度程序代码有两个问题:

1. 问题在 t=0 时,只有 T4 准备好,但请注意 T1 的发布时间为 10,根据我对 T1 的 if 语句,我有0 % (10 + 10) == 0,即使 T1 还没有准备好,它也会被释放。我可以引入一个布尔值来告诉任务是否已被释放,但是有没有更聪明的方法来做到这一点而不引入额外的变量?

2. 问题在 t=26,没有任务准备好,但是,任务 T2 被释放。根据我对 T2 的 if 语句,我有26 % (3 + 10) == 0.

void prvTaskSchedulerProcess(void *pvParameters) {

...

uint32_t uCurrentTickCount = 0;
gll_t* pTaskList = (gll_t*) pvParameters;
WorkerTask_t* pWorkerTask = NULL;

while (true) {

    for (uint8_t uIndex = 0; uIndex < pTaskList->size; uIndex++) {

        pWorkerTask = gll_get(pTaskList, uIndex);

        // Check if the task is ready to be executed
        if ( (uCurrentTickCount % (pWorkerTask->uReleaseTime + pWorkerTask->uPeriod) ) == 0) ){

            // Dispatch the ready task
            vTaskResume(pWorkerTask->xHandle); 
        }
    }

    uCurrentTickCount++;
    // Sleep the scheduler task, so the other tasks can run
    vTaskDelay(TASK_SCHEDULER_TICK_TIME * SCHEDULER_OUTPUT_FREQUENCY_MS); 
}

}

使用额外的标志似乎是一个简单的解决方案。但是有人告诉我,引入标志变量并不是最好的解决方案,因为它会降低代码的可读性和可维护性。因此,我想避免使用它们。如果不使用额外的标志(可能更正我的 if 语句条件),如何实现正确的任务调度?

标签: operating-systemembeddeddispatcherfreertostaskscheduler

解决方案


请注意,如果您正在恢复的任务没有完成之前的操作并再次挂起,那么以这种方式使用 vTaskResume() 本身就很危险。有关更完整的解释,请参阅 API 文档https://www.freertos.org/taskresumefromisr.html


推荐阅读