从列表中定期调度任务 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
我正在使用 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