已更新 2025年7月
FreeRTOS 协程
局限和限制
与同等任务相比,协程的优势是使用的 RAM 较少,但代价是 使用协程时存在一些限制条件。与任务相比,协程的限制性更强,使用起来也更复杂 。
-
共享堆栈
当协程阻塞时,协程的堆栈无法维持。这意味着在堆栈上分配的变量 很可能丢失其值。要克服这一问题, 需将在阻塞调用中维持其值的变量声明为静态。例如:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle,2 UBaseType_t uxIndex )3{4 static char c = 'a';56 // Co-routines must start with a call to crSTART().7 crSTART( xHandle );89 for( ;; )10 {11 // If we set c to equal 'b' here ...12 c = 'b';1314 // ... then make a blocking call ...15 crDELAY( xHandle, 10 );1617 // ... c will only be guaranteed to still18 // equal 'b' here if it is declared static19 // (as it is here).20 }2122 // Co-routines must end with a call to crEND().23 crEND();24}共享堆栈的另一个结果是,能从协程函数本身调用可能导致协程阻塞的 API 函数, 而不能从协程调用的函数中调用 。例如:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )2{3 // Co-routines must start with a call to crSTART().4 crSTART( xHandle );56 for( ;; )7 {8 // It is fine to make a blocking call here,9 crDELAY( xHandle, 10 );1011 // but a blocking call cannot be made from within12 // vACalledFunction().13 vACalledFunction();14 }1516 // Co-routines must end with a call to crEND().17 crEND();18}1920void vACalledFunction( void )21{22 // Cannot make a blocking call here!23} -
switch 语句的使用
FreeRTOS 下载中的默认协程实现不允许 在 switch 语句中进行阻塞调用。例如:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )2{3 // Co-routines must start with a call to crSTART().4 crSTART( xHandle );56 for( ;; )7 {8 // It is fine to make a blocking call here,9 crDELAY( xHandle, 10 );1011 switch( aVariable )12 {13 case 1 : // Cannot make a blocking call here!14 break;15 default: // Or here!16 }17 }1819 // Co-routines must end with a call to crEND().20 crEND();21}