从列表中定期调度任务 FreeRTOS

Dispatching Tasks periodically from a List 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 语句条件),如何实现正确的任务分派?

要解决问题 2,请使用以下条件代替现有条件。

if ((uCurrentTickCount % pWorkerTask->uPeriod) == pWorkerTask->uReleaseTime)

要解决问题 1(和问题 2),请使用以下条件。

if ((uCurrentTickCount >= pWorkerTask->uReleaseTime) &&
    ((uCurrentTickCount % pWorkerTask->uPeriod) == (pWorkerTask->uReleaseTime % pWorker->uPeriod)))

请注意,以这种方式使用 vTaskResume() 本身就很危险,即使您正在恢复的任务有可能未完成其先前的操作并再次自行挂起,这种可能性很小。请参阅 API 文档以获得更完整的解释 https://www.freertos.org/taskresumefromisr.html