Follow+Star Public Account Number, don’t miss wonderful content
Author | 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:
Coroutines mainly have three states: Running, Ready, and Blocked.
-
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();}
#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();}
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 ————
● 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.