一.任务调度机制
- 可抢占:高优先级的任务先运行
- 时间片轮转:同优先级的任务轮流执行
- 空闲任务礼让:如果有同是优先级为0的其他就绪任务,空闲任务主动放弃一次运行机会
- 函数调用vTaskDelay( xDelay5ms )可以主动放弃任务执行,让出CPU使用权
- 系统中最低优先级中断比最高优先级任务大
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);
xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
=========================================================================
二.空闲任务函数 portTASK_FUNCTION( prvIdleTask, pvParameters )
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
( void ) pvParameters;
portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );
for( ; ; )
{
prvCheckTasksWaitingTermination();
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
{
taskYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
#if ( configUSE_IDLE_HOOK == 1 )
{
extern void vApplicationIdleHook( void );
vApplicationIdleHook();
}
#endif /* configUSE_IDLE_HOOK */
#endif /* configUSE_TICKLESS_IDLE */
}
}
FreeRTOS操作系统中配置项 configUSE_PREEMPTION == 1表示同等优先级之间可抢占,配置项configIDLE_SHOULD_YIELD == 1 表示表示主动礼让,只有在任务可抢占的情况下,才考虑空闲礼让的情况。
如果 配置选项配置为configUSE_PREEMPTION == 0不抢占的情况,那么直接进行礼让 taskYIELD(),任何其他的情况发生都是直接礼让。可抢占的时候可以配置是否礼让,不抢占中有礼让的这一种情况。
在空闲任务portTASK_FUNCTION中,会对任务就绪链表里的任务进行一次判断,如果当前任务就绪链表长度listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) )大于1,那么说明链表里面出了空闲任务外,还有其他的优先级为0的任务。那么空闲任务马上就做出任务礼让。其中tskIDLE_PRIORITY =0,即pxReadyTasksLists[ 0 ] 。
礼让了其他任务以后,空闲任务函数执行 taskYIELD() 礼让其他任务,让其他任务先运行,函数执行到taskYIELD()后马上启动任务调度函数,任务调度函数执行任务Task1,任务Task2,任务Task3,等这三个任务运行完后,再执行回去执行空闲任务函数,从上次礼让的位置继续执行下去。
=========================================================================
可抢占可礼让的情况下,任务执行的的顺序是idle_task 执行一会后,马上执行任务Task 1,是否会执行任务Task 2,任务Task 3还得看任务是否会轮流执行。
在 xTaskIncrementTick函数中可以看到,只有配置成configUSE_PREEMPTION == 1可抢占和 configUSE_TIME_SLICING == 1时间片轮转的情况,任务Task2才可以得到执行。 不抢占不轮转,任务Task2永远得不到运行。