FreeRTOS 原理 --- 临界区(critical section)
关调度器
void vTaskSuspendAll( void ) { /* A critical section is not required as the variable is of type BaseType_t. Please read Richard Barry's reply in the following link to a post in the FreeRTOS support forum before reporting this as a bug! - http://goo.gl/wu4acr */ ++uxSchedulerSuspended; }
通过一个变量表示是否关调度器,大于0表示关调度器,等于0表示没有关调度器。
关调度器后,不允许主动或被动线程切换(因为关调度器和开调度器是成对出现,如果 delay 主动让出CPU,其他线程没有开调度器操作,delay 时间到也回不去,因为 tick 中断也 bypass 了,无法检查时间到从而切换线程),切换前都会检查是否关了调度器,关状态还主动切换会断言。
如下 delay 主动切换线程
void vTaskDelay( const TickType_t xTicksToDelay ) { BaseType_t xAlreadyYielded = pdFALSE; /* A delay time of zero just forces a reschedule. */ if( xTicksToDelay > ( TickType_t ) 0U ) { configASSERT( uxSchedulerSuspended == 0 );
如下 tick 中断被动切换线程,如果关调度器,直接 bypass
BaseType_t xTaskIncrementTick( void ) { TCB_t * pxTCB; TickType_t xItemValue; BaseType_t xSwitchRequired = pdFALSE; /* Called by the portable layer each time a tick interrupt occurs. Increments the tick then checks to see if the new tick value will cause any tasks to be unblocked. */ traceTASK_INCREMENT_TICK( xTickCount ); if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
关中断
如果线程和中断都会修改共同的数据,就需要通过关中断来实现临界区