Understanding the Differences Between Coroutines and Tasks in RTOS

Follow+Star Public Account Number, don’t miss wonderful content

Understanding the Differences Between Coroutines and Tasks in RTOS

Author | strongerHuang

WeChat Public Account | strongerHuang

We are familiar with processes and threads, but their names might be different in RTOS systems. The familiar term is Task (Task), which is similar to Thread (Thread). You will find that in some places, RTOS tasks are also called threads.

However, there is another program in RTOS that is not so common, called Coroutine. Today, we will briefly discuss the content of coroutines and tasks in RTOS, as well as their differences.

What is a Coroutine?

A coroutine is short for collaborative program, with the English name Coroutine.

A coroutine is a more lightweight concurrent programming model and program component than a thread, allowing multiple coroutines to execute within a single thread, and these coroutines can suspend and resume during execution, thus achieving concurrent execution.

Let’s understand the relationship between processes, threads, and coroutines through a diagram:

Understanding the Differences Between Coroutines and Tasks in RTOS

Coroutines mainly have three states: Running, Ready, and Blocked.

Understanding the Differences Between Coroutines and Tasks in RTOS

  • Running: When a coroutine is actually executing, it is said to be in the running state, and the current coroutine is using the processor.

  • Ready: A ready coroutine is one that can execute (not blocked) but is currently not executing.

  • Blocked: If a coroutine is currently waiting for a time event or an external event, it is said to be in a blocked state.

Coroutine Function Structure:

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

Start by calling crSTART(), and end with crEND(); the coroutine function should not return any value.

It is actually somewhat similar to tasks in RTOS, but there are also many differences (we will discuss the differences later).

Coroutine Example

The above description may be a bit abstract for many beginners, and somewhat difficult to understand, so here we will describe coroutines with code examples.

1. Create a Simple LED Blinking Coroutine

void vFlashCoRoutine( CoRoutineHandle_t xHandle,                      UBaseType_t uxIndex ){    crSTART( xHandle );
    for( ;; )    {        // Delay for a while        crDELAY( xHandle, 10 );
        // Blink (toggle LED)        vParTestToggleLED( 0 );    }
    crEND();}

2. Schedule Coroutine

Schedule the coroutine by calling vCoRoutineSchedule(). It can be done when the task is idle:

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

Or by looping while not executing other functions:

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

3. Create Coroutine and Start Task Scheduler

For example: create and start the scheduler in the main() function.

#include "task.h"
#include "croutine.h"
#define PRIORITY_0 0
void main( void ){    // Create coroutine    xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 );
    // Enable scheduler.    vTaskStartScheduler();}
4. Extension: Using Index Parameter
Suppose we want to create 8 such coroutines from the same function. Each coroutine will blink different LEDs at different speeds. The index parameter can be used to distinguish between coroutines in the coroutine function.
Here, we create 8 coroutines and pass a different index to each coroutine:
#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();}
Coroutine functions are also extended, so each coroutine uses different LEDs and blinking speeds.
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( ;; )    {        // Set delay based on index        crDELAY( xHandle, iFlashRate[ uxIndex ] );
        // LED blinking        vParTestToggleLED( iLEDToFlash[ uxIndex ] );    }    crEND();}

Differences Between Coroutines and Tasks in RTOS

The above example introduces the content of coroutines. Friends who have used RTOS (tasks) programming should be able to understand it. In fact, tasks and coroutines have many similarities, but also many differences:

1. Scheduling and Management

Tasks are scheduled and managed by the operating system, while coroutines do not require a system scheduler for management; they are managed by the user.

2. Resource Usage

Tasks occupy more system resources through system calls, while coroutines execute within a single thread and do not consume a lot of system resources like multithreading.

3. RAM Usage

Coroutines do not occupy system resources, making them more suitable for processors with limited RAM, such as early 8-bit and 16-bit MCUs.

4. Limitations

The advantage of coroutines is that they use less RAM, but the downside is that coroutines have more limitations. Compared to tasks, coroutines are more restrictive and more complex to use.

5. Execution Efficiency

Since coroutine switching is controlled by the program itself, with no overhead from thread switching, coroutines generally have higher execution efficiency.

6. ……

In the past, MCU resources and performance were relatively low, and some RTOS (like FreeRTOS) had coroutine functionality. However, with the improvement of MCU resources and performance, coroutines have been replaced by threads (tasks).

———— END ————

Understanding the Differences Between Coroutines and Tasks in RTOS

● Column “Embedded Tools”

● Column “Embedded Development”

● Column “Keil Tutorial”

● Selected Tutorials from Embedded Column

Follow the public account and reply “Join Group” to join the technical exchange group according to the rules, or reply “1024” to see more content.

Click “Read the Original” to see more sharing.

Leave a Comment