查看: 630|回复: 0

[分享] RTOS中协程与任务的区别

[复制链接]
  • TA的每日心情
    开心
    2 小时前
  • 签到天数: 239 天

    连续签到: 23 天

    [LV.7]常住居民III

    47

    主题

    7148

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    12636
    最后登录
    2025-9-9
    发表于 2025-2-24 13:29:56 | 显示全部楼层 |阅读模式
    进程和线程我们都很熟悉了,在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 0void 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    8void 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资源和性能的提升,协程已经被线程(任务)替代了。


    哎...今天够累的,签到来了~
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-9-9 12:00 , Processed in 0.080617 second(s), 19 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表