在嵌入式实时操作系统中,都会有空闲任务的存在,这个任务是伴随着操作系统启动之后而存在的。正常情况来说,系统不挂掉,空闲任务都会一直存在。

freeRTOS 调度器启动时,自动创建空闲任务,以确保系统中始终存在一个能够运行的任务。 它是以最低优先级创建,以确保如果有更高的优先级的任务处于准备就绪状态,则空闲任务不使用任何 CPU 时间,让渡出CPU的使用权给到更高优先级的就绪任务去执行。

freeRTOS中创建空闲任务的代码如下:

  1. xTaskCreate( prvIdleTask,
  2. configIDLE_TASK_NAME,
  3. configMINIMAL_STACK_SIZE,
  4. (void* )NULL,
  5. portPRIVILEGE_BIT,
  6. &xIdleTaskHandle );

空闲任务的作用:

(1)释放内存

如果一个任务删除另外的任务,那个被删除的任务的TCB块和堆栈空间会被马上释放掉;

如果一个任务自己删除了自己,那么这个删除自身的任务的TCB块和堆栈空间是由空闲任务进行回收的,空闲任务会去查询有没有自己删除自己的任务,如果有就会去回收这个任务的TCB块和堆栈空间。如下:

forum.jpg



(2)处理空闲优先级任务

在freeRTOS中,如果使用抢占式的调度方式,具有相同优先级的任务是通过时间片的方式获取CPU使用权限的。通过时间片共享同一个优先级的多个任务,如果共享的优先级大于空闲优先级,并假设没有更高优先级的任务,这些任务应该获得相同的处理器时间。

但是在空闲任务优先级相同的情况下,这点是有些不同的。

如果有与空闲任务相同的优先级的其他任务,在宏configIDLE_SHOULD_YIELD 为1时,空闲任务是不必等到时间片耗尽再进行任务切换的。意思是:时间片轮转到空闲任务执行时,如果这个时候检查到还有其他的任务处于就绪状态,空闲任务就直接把cpu执行权交给其他的任务,而不需要等待空闲任务的时间片使用完。

当然,这种情况是需要满足下面的条件才能够实现的:

1)系统调度方式使用的是抢占式的方式2)有与空闲任务相同优先级的其他任务3)宏configIDLE_SHOULD_YIELD设置为1

如下例所示:

假设有三个任务A、B、C,他们的任务优先级与空闲任务I相同,并且宏 configIDLE_SHOULD_YIELD 为 1,那么任务A、B、C、I 的执行如下图演示:

forum.jpg


假设上下文切换周期性的发生在T0、T1…T6时刻,当T2时刻是空闲任务执行,然后发现任务A处于就绪,空闲任务I就会把cpu使用权让给任务A。但是这个时候下,任务A执行的时间片变短,因为空闲任务I占据了一部分的时间。这样相比之下,任务A比任务B、C的执行时间就变短了。

有什么办法解决这个问题吗?可以按照下面的方法考虑一下:

1)将跟空闲任务优先级相同的其他任务使用空闲钩子函数实现;2)用户任务的任务优先级大于空闲任务的优先级;3)设置configIDLE_SHOULD_YIELD为0,不让空闲任务让出cpu使用权;


(3)执行空闲任务钩子函数

空闲任务钩本质就是一个函数,这个函数需要用户去实现,但是RTOS中规定了函数的名字和参数。如下:

voidvApplicationIdleHook(void);

这个钩子函数在每个空闲任务周期都会被调用。

要使用这个钩子函数的话,还需要再FreeRTOSConfig.h文件中将一个宏置 1,如下:

#defineconfigUSE_IDLE_HOOK 1

特别要注意的是:空闲任务的钩子函数里面不可以调用会引起阻塞的API,比如消息队列、vTaskDelay()、消息邮箱、信号量之类的。