专栏名称: 21ic电子网
即时传播最新电子科技信息,汇聚业界精英精彩视点。
目录
相关文章推荐
21ic电子网  ·  RTOS中协程与任务的区别 ·  昨天  
21ic电子网  ·  MCU里硬件CRC对数据长度对齐有要求? ·  2 天前  
半导体行业联盟  ·  Wolfspeed CEO,被免职 ·  6 天前  
半导体行业联盟  ·  突发!10座半导体厂项目被叫停 ·  1 周前  
51好读  ›  专栏  ›  21ic电子网

RTOS中协程与任务的区别

21ic电子网  · 公众号  · 半导体  · 2024-11-24 15:47

正文


进程和线程我们都很熟悉了,在RTOS系统中的叫法可能不一样,我们熟悉的就是任务(Task),这个和线程(Thread)比较近似,你会发现有些地方RTOS的任务,也叫线程。


但是在RTOS中还有一种不是那么常见的程序,叫协程。今天就来简单聊聊RTOS中协程和任务的内容,以及它们的区别。


什么是协程?

协程,是协同程序的缩写,英文名Coroutine。


协程是一种比线程更加轻量级的并发编程模型、程序组件它允许单个线程内执行多个协程,而这些协程可以在执行过程中挂起和恢复,从而实现并发执行的效果。


这里通过一张图来了解下进程、线程和协程的关系:

协程主要由三种状态:运行(Runing)、就绪(Ready)、阻塞(Blocked)。


  • 运行:当协程实际执行时,它被称为处于运行状态,当前协程正在使用处理器。

  • 就绪:就绪的协程是那些能够执行(未阻塞)但目前未执行的协程。 

  • 阻塞:如果协程当前正在等待时间事件或外部事件,则该协程被称为处于阻塞状态 。


协程的函数结构:

void vACoRoutineFunction( CoRoutineHandle_t xHandle,                          UBaseType_t uxIndex ){    crSTART( xHandle );
for( ;; ) { //-- Co-routine application code here. -- }
crEND();}

以调用 crSTART() 开始,调用 crEND() 结束,协程函数不应返回任何值。


它其实和RTOS中的任务有点类似,但也有很多不同(最后说区别)


协程的案例

上面通过文字描述可能对于很多新手有点抽象,也有点难理解,这里结合代码案例给大家描述协程。


1、创建一个简单的LED闪烁协程 

void vFlashCoRoutine( CoRoutineHandle_t xHandle,                      UBaseType_t uxIndex ){    crSTART( xHandle );
for( ;; ) {        // 延时一段时间 crDELAY( xHandle, 10 );
        // 闪烁(翻转LED) vParTestToggleLED( 0 ); }
crEND();}


2、调度协程

通过调用 vCoRoutineSchedule() 来调度协程。可以在任务空闲的时候:

void vApplicationIdleHook( void ){    vCoRoutineSchedule( void );}


或者在没有执行其他函数的时候,循环调用:

void vApplicationIdleHook( void ){    for( ;; )    {        vCoRoutineSchedule( void );    }}


3、创建协程并启动任务调度器

比如:在 main() 函数中创建并启动调度器。

#include "task.h"#include "croutine.h"
#define PRIORITY_0 0
void main( void ){    // 创建协程    xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 );
    //启用调度器. vTaskStartScheduler();}


4、扩展:使用索引参数
假设我们要从同一函数中创建 8 个这样的协程。每个协程将 以不同速度闪烁不同的 LED。索引参数可用于在协程函数中区分协程。

这里,我们创建 8 个协程,并向每个协程传递不同的索引:
#include "task.h"#include "croutine.h"
#define PRIORITY_0 0#define NUM_COROUTINES 8
void main( void ){ int i;
for( i = 0; i < NUM_COROUTINES; i++ ) { // This time i is passed in as the index. xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, i ); }
// NOTE: Tasks can also be created here!
// Start the RTOS scheduler. vTaskStartScheduler();}

协程函数也被扩展,因此每个协程使用的 LED 和闪烁速度都不同。
const int iFlashRates[ NUM_COROUTINES ] = { 10, 20, 30, 40, 50, 60, 70, 80 };const int iLEDToFlash[ NUM_COROUTINES ] = { 0, 1, 2, 3, 4, 5, 6, 7 }
void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ){ crSTART( xHandle );
for( ;; ) {        // 根据索引设定延时 crDELAY( xHandle, iFlashRate[ uxIndex ] );
// LED闪烁 vParTestToggleLED( iLEDToFlash[ uxIndex ] );    } crEND();}


RTOS中协程与任务的区别

上面通过案例介绍的协程的内容,有使用过RTOS(任务)编程的朋友应该都能看明白,其实任务和协程有很多相似之处,但也有很多区别:

1、调度和管理

任务由操作系统进行调度和管理,而协程不需要系统调度器来管理,而是由用户自己管理。


2、占用资源

任务通过系统调用,会占用更多系统资源,而协程在单个线程中执行,不会像多线程那样消耗大量的系统资源。


3、RAM使用量

协程不占用系统资源,因此协程更适合用于RAM较小的处理器,如早期的8位、16位MCU。


4、限制

协程的优势是使用的 RAM 较少,但代价是协程存在更多的限制。与任务相比,协程的限制性更强,使用起来也更复杂 。


5、执行效率

由于协程的切换是由程序自身控制的,没有线程切换的开销,因此协程在执行效率上通常更高。


6、......


早期,MCU资源和性能相对都不高,有些RTOS(如FreeRTOS)都有协程的功能。但是,随着MCU资源和性能的提升,协程已经被线程(任务)替代了。

------------ END ------------


温馨提示:

因最近微信公众平台推送规则改变,很多读者反馈没有及时看到更新的文章。根据最新规则,建议多点击“推荐阅读、分享、收藏”等,成为常读用户。


推荐阅读:


请点下【在看】给小编加鸡腿