我正在使用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语句条件)?答案 0 :(得分:2)
请注意,以这种方式使用vTaskResume()会产生内在的危险,即使您恢复的任务极少有机会未完成其先前的操作并再次暂停其自身,也是如此。有关更完整的说明,请参见API文档https://www.freertos.org/taskresumefromisr.html
答案 1 :(得分:1)
要解决问题2,请使用以下条件代替现有条件。
if ((uCurrentTickCount % pWorkerTask->uPeriod) == pWorkerTask->uReleaseTime)
要解决问题1(和问题2),请使用以下条件。
if ((uCurrentTickCount >= pWorkerTask->uReleaseTime) &&
((uCurrentTickCount % pWorkerTask->uPeriod) == (pWorkerTask->uReleaseTime % pWorker->uPeriod)))