1. 代码
这次反着来,我们先看一段代码;
任务 1:任务 1 的大循环里,创建任务 2,然后休眠一段时间 任务 2:打印一句话,然后就删除自己
任务1代码:
void vTask1( void *pvParameters )
{
const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );
BaseType_t ret;
for( ;; )
{
printf("Task1 is running\r\n");
ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
if (ret != pdPASS)
printf("Create Task2 Failed\r\n");
vTaskDelay( xDelay100ms );
}
}
任务2代码:
void vTask2( void *pvParameters )
{
printf("Task2 is running and about to delete itself\r\n");
vTaskDelete(xTask2Handle);
}
main 函数代码如下:
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
vTaskStartScheduler();
return 0;
}
2.调试环境
3.运行结果
4.运行过程分析
- main 函数中创建任务 1,优先级为 1。任务 1 运行时,它创建任务 2,任
务 2 的优先级是 2。 - 任务 2 的优先级最高,它马上执行。
- 任务 2 打印一句话后,就删除了自己。
- 任务 2 被删除后,任务 1 的优先级最高,轮到任务 1 继续运行,它调用
vTaskDelay()进入 Block 状态。 - 任务 1 Block 期间,轮到 Idle 任务执行:它释放任务 2 的内存(TCB、栈)。
- 时间到后,任务 1 变为最高优先级的任务继续执行.
- 一直循环下去
5. 关闭空闲任务
在任务 1 的函数中,如果不调用 vTaskDelay,会出现一个什么样的情况呢? 屏蔽这句代码:
vTaskDelay( xDelay100ms );
6.运行结果
7.运行结果分析
在任务 1 的函数中,如果不调用 vTaskDelay,则 空闲任务Idle 没有机会执行,它就无法释放创建任务 2 是分配的内存。而任务 1 在不断地创建任务,不断地消耗内存,最终内存耗尽再也无法创建新的任务。
8.空闲任务的定义
空闲任务是启动RTOS调度器时由内核自动创建的任务,这样可以确保至少有一个任务在运行。空闲任务具有最低任务优先级,这样如果有其它更高优先级的任务进入就绪态就可以立刻让出CPU。空闲任务要么处于就绪态, 要么处于运行态,永远不会阻塞。
空闲任务的优先级为 0,这意味着一旦某个用户的任务变为就绪态,那么空闲任务马上被切换出去,让这个用户任务运行。在这种情况下,我们说用户任务"抢占"了空闲任务,这是由调度器实现的。
删除任务后,空闲任务用来释放RTOS分配给被删除任务的内存。 因此,在应用中使用vTaskDelete()函数后确保空闲任务能获得处理器时间就很重要了。除此之外,空闲任务没有其它有效功能,所以可以被合理的剥夺处理器时间,并且它的优先级也是最低的。
9.钩子函数
空闲任务的循环每执行一次,就会调用一次钩子函数。 钩子函数的作用有这些:
- 会执行一些比较低级的任务
- 测量系统的空闲时间,空闲任务执行时,代表着所有高优先级的任务都停止了,所以可以根据系统的空闲时间计算处理器的占用率
- 让系统进入省电模式
总结
|