3-FreeRTOS任务和协程(下)

简介: 3-FreeRTOS任务和协程

2-协程

2.1-协同状态

协程仅适用于对RAM有限制的处理器,一般情况下32位MCU是不会使用的(在这里还是给大家说一下,基础理论知识就全点)。

2.1.1 运行当协程实际执行时,我们称其处于运行状态。当前处理器正在工作。2.1.2 就绪就绪的协程是那些能够执行(它们没有被阻塞)但目前没有执行的。协程可能处于Ready状态,一是 另一个具有同等或更高优先级的协程已经处于Running状态;二是任务处于Running状态(只有当应用程序同时使用任务和协程时,才会出现这种情况)。2.1.3 阻塞

如果一个协程当前正在等待一个临时或外部事件,那么它就被称为处于Blocked状态。例如,如果一个协程调用crDELAY(),它将阻塞(被置于阻塞状态),直到延迟周期超时,一个临时事件。阻塞的协程无法用于调度。

下面是协程的通信图:


2.2 协程的实现

协程的结构如下:

1void vACoRoutineFunction( CoRoutineHandle_t xHandle,
 2UBaseType_t uxIndex )
 3{
 4crSTART( xHandle );
 5
 6for( ;; )
 7{
 8-- Co-routine application code here. --
 9}
10
11crEND();
12}

类型crCOROUTINE_CODE被定义为一个返回void并将CoRoutineHandle_t和索引作为参数的函数。实现协程的所有函数都应该是这种类型的(上面的这段代码)。

协程的创建是通过xCoRoutineCreate()来进行的。


注意:

所有协程函数都必须以调用crSTART()开始。

所有协程函数都必须以对crEND()的调用结束。

协程函数不应该返回,因此通常作为连续循环实现。

可以从单个协程函数创建许多协程。

提供 uxIndex 参数是为了区分此类 协程。

2.3-协程优先级

协程的优先级从0到(configMAX_CO_ROUTINE_PRIORITIES - 1)。configMAX_CO_ROUTINE_PRIORITIES在FreeRTOSConfig.h中定义,可以在应用程序的基础上设置。优先级和任务一样数字越大优先级越高。

协程优先级只与其他协程相关。如果在同一个应用程序中混合了任务和协程,那么任务的优先级始终比协程的优先级高。


2.4- 协程调度

协程是通过重复调用vCoRoutineSchedule() 来调度的。调用 vCoRoutineSchedule() 的最佳位置是从空闲任务钩子。即使您的应用程序只使用协程,也会出现这种现象,因为空闲任务仍将在调度程序启动时自动创建。

2.5- 协程和任务的混合

在空间任务中调度协程是允许任务和协程的混合的。这种方式只有当协程优先级低于空闲任务的优先级时,这种方式下才能执行。

2.5.1-局限性和复杂性和任务相比来说,协程的好处是降低了RAM的使用空间,但是这些也会带来一定的限制。比如局限性以及复杂性。2.5.2堆栈共享当协程阻塞时,携程的堆栈时不会被保存的,这样即使在堆栈上有再多的变量,也会丢失。因此为了能够解决这个问题,需要声明一个在阻塞时保持调用的变量,作为静态。例如:

1void vACoRoutineFunction( CoRoutineHandle_t xHandle,
 2UBaseType_t uxIndex )
 3{
 4static char c = 'a';
 5
 6// Co-routines must start with a call to crSTART().
 7crSTART( xHandle );
 8
 9for( ;; )
10{
11// If we set c to equal 'b' here ...
12c = 'b';
13
14// ... then make a blocking call ...
15crDELAY( xHandle, 10 );
16
17// ... c will only be guaranteed to still 
18// equal 'b' here if it is declared static
19// (as it is here).
20}
21
22// Co-routines must end with a call to crEND().
23crEND();
24}


堆栈共用的另一种结果是,可能导致协程阻塞API函数的调用只能来自于协程函数本身,而不是协程函数调用的函数。


1例如:
 2void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
 3{
 4// Co-routines must start with a call to crSTART().
 5crSTART( xHandle );
 6
 7for( ;; )
 8{
 9// It is fine to make a blocking call here,
10crDELAY( xHandle, 10 );
11
12// but a blocking call cannot be made from within
13// vACalledFunction().
14vACalledFunction();
15}
16
17// Co-routines must end with a call to crEND().
18crEND();
19}
20
21void vACalledFunction( void )
22{
23// Cannot make a blocking call here!
24}

2.5.3 switch语句的应用FreeRTOS文件中包含的默认协程实现不允许从switch语句中进行阻塞调用。

1void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
 2{
 3// Co-routines must start with a call to crSTART().
 4crSTART( xHandle );
 5
 6for( ;; )
 7{
 8// It is fine to make a blocking call here,
 9crDELAY( xHandle, 10 );
10
11switch( aVariable )
12{
13case 1 : // Cannot make a blocking call here!
14break;
15default: // Or here!
16}
17}
18
19// Co-routines must end with a call to crEND().
20crEND();
21}

2.6协程例子2.6.1 创建LED协程

1void vFlashCoRoutine( CoRoutineHandle_t xHandle,
 2UBaseType_t uxIndex )
 3{
 4// Co-routines must start with a call to crSTART().
 5crSTART( xHandle );
 6
 7for( ;; )
 8{
 9// Delay for a fixed period.
10crDELAY( xHandle, 10 );
11
12// Flash an LED.
13vParTestToggleLED( 0 );
14}
15
16// Co-routines must end with a call to crEND().
17crEND();
18}

2.6.2 协程调度

协同例程是通过重复调用 vCoRoutineSchedule()来调度的。执行此操作的最佳位置是从空闲任务中编写空闲任务挂钩。首先确保在FreeRTOSConfig.h 中将configUSE_IDLE_HOOK设置为 1。然后将空闲任务钩子编写为:

1void vApplicationIdleHook( void )
 2{
 3vCoRoutineSchedule( void );
 4}
 5或者,如果空闲任务不执行任何其他函数,从循环中调用vCoRoutineSchedule()会更有效:
 6void vApplicationIdleHook( void )
 7{
 8for( ;; )
 9{
10vCoRoutineSchedule( void );
11}
12}

2.6.3 创建协程并启动RTOS调度

1#include "task.h"
 2#include "croutine.h"
 3
 4#define PRIORITY_0 0
 5
 6void main( void )
 7{
 8// In this case the index is not used and is passed 
 9// in as 0.
10xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 );
11
12// NOTE: Tasks can also be created here!
13
14// Start the RTOS scheduler.
15vTaskStartScheduler();
16}

2.6.4 扩展现在假设我们要从同一个函数创建 8 个这样的协程。每个协程将闪烁不同的 LED 以不同的速率显示。index 参数可用于区分协程函数本身。

1#include "task.h"
 2#include "croutine.h"
 3
 4#define PRIORITY_0 0
 5#define NUM_COROUTINES 8
 6
 7void main( void )
 8{
 9int i;
10
11for( i = 0; i < NUM_COROUTINES; i++ )
12{
13// This time i is passed in as the index.
14xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, i );
15}
16
17// NOTE: Tasks can also be created here!
18
19// Start the RTOS scheduler.
20vTaskStartScheduler();
21}
22还扩展了协程功能,因此每个程序都使用不同的LED和闪光率。
23const int iFlashRates[ NUM_COROUTINES ] = { 10, 20, 30, 40, 50, 60, 70, 80 };
24const int iLEDToFlash[ NUM_COROUTINES ] = { 0, 1, 2, 3, 4, 5, 6, 7 }
25
26void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
27{
28// Co-routines must start with a call to crSTART().
29crSTART( xHandle );
30
31for( ;; )
32{
33// Delay for a fixed period. uxIndex is used to index into
34// the iFlashRates. As each co-routine was created with
35// a different index value each will delay for a different
36// period.
37crDELAY( xHandle, iFlashRate[ uxIndex ] );
38
39// Flash an LED. Again uxIndex is used as an array index,
40// this time to locate the LED that should be toggled.
41vParTestToggleLED( iLEDToFlash[ uxIndex ] );
42}
43
44// Co-routines must end with a call to crEND().
45crEND();
46}

****因个人创作与翻译,难免有错误地方,希望各位道友指正。我会在后面CSDN进行修改(公众号当前只支持修改20个字)。*****


相关文章
|
8月前
|
数据采集 Java Python
多线程与多任务异步协程高效爬虫
多线程与多任务异步协程高效爬虫
|
4月前
|
测试技术 调度 项目管理
Python多任务协程:编写高性能应用的秘密武器
Python多任务协程:编写高性能应用的秘密武器
25 1
|
12月前
|
算法 编译器 API
|
Java 数据库 芯片
物无定味适口者珍,Python3并发场景(CPU密集/IO密集)任务的并发方式的场景抉择(多线程threading/多进程multiprocessing/协程asyncio)
一般情况下,大家对Python原生的并发/并行工作方式:进程、线程和协程的关系与区别都能讲清楚。甚至具体的对象名称、内置方法都可以如数家珍,这显然是极好的,但我们其实都忽略了一个问题,就是具体应用场景,三者的使用目的是一样的,换句话说,使用结果是一样的,都可以提高程序运行的效率,但到底那种场景用那种方式更好一点?
物无定味适口者珍,Python3并发场景(CPU密集/IO密集)任务的并发方式的场景抉择(多线程threading/多进程multiprocessing/协程asyncio)
|
Go 调度
工作用Go: 异步任务怎么写1 | Go协程与异步
工作用Go: 异步任务怎么写1 | Go协程与异步
520 0
工作用Go: 异步任务怎么写1 | Go协程与异步
|
Java 数据库 芯片
物无定味适口者珍,Python3并发场景(CPU密集/IO密集)任务的并发方式的场景抉择(多线程threading/多进程multiprocessing/协程asyncio)
一般情况下,大家对Python原生的并发/并行工作方式:进程、线程和协程的关系与区别都能讲清楚。甚至具体的对象名称、内置方法都可以如数家珍,这显然是极好的,但我们其实都忽略了一个问题,就是具体应用场景,三者的使用目的是一样的,话句话说,使用结果是一样的,都可以提高程序运行的效率,但到底那种场景用那种方式更好一点? 这就好比,目前主流的汽车发动机变速箱无外乎三种:双离合、CVT以及传统AT。主机厂把它们搭载到不同的发动机和车型上,它们都是变速箱,都可以将发动机产生的动力作用到车轮上,但不同使用场景下到底该选择那种变速箱?这显然也是一个问题。
|
存储 缓存 算法
Python 多任务3: 协程
Python 多任务3: 协程
152 0
|
程序员 Python
Python3简单实现多任务(线程/协程篇)
写在前面 上一篇文章[Python3简单实现多任务(多进程篇)]已经介绍了python多进程实现多任务的简单实现方法; 这次讲一讲python创建多任务另外两种常见的方式: 协程和线程 线程多任务实现1:直接使用Thread创建线程 ...
1161 0
|
22天前
|
网络协议 调度 开发者
python中gevent基于协程的并发编程模型详细介绍
`gevent`是Python的第三方库,提供基于协程的并发模型,适用于I/O密集型任务的高效异步编程。其核心是协程调度器,在单线程中轮流执行多个协程,通过非阻塞I/O实现高并发。主要特点包括协程调度、事件循环的I/O模型、同步/异步编程支持及易用性。示例代码展示了一个使用`gevent`实现的异步TCP服务器,当客户端连接时,服务器以协程方式处理请求,实现非阻塞通信。
14 0
|
2月前
|
并行计算 调度 开发者
深入浅出Python协程:提升你的异步编程效率
在当今快速发展的软件开发领域,异步编程已成为提高程序性能和用户体验的关键技术。Python,作为一门广泛使用的高级编程语言,其协程(Coroutine)功能为开发者提供了强大的异步编程工具。本文将从协程的基本概念入手,通过实例深入浅出地讲解如何在Python中有效利用协程来提升异步编程的效率和可读性。我们将探讨协程的工作原理、与传统多线程/多进程相比的优势,以及如何在实际项目中应用协程来解决复杂的并发问题。通过本文的学习,读者将能够掌握Python协程的核心知识,为构建高效、可维护的异步应用奠定坚实基础。