协程简介

关于协程的概念,其实由来已久,在介绍协程的概念之前先简单回顾下我们通常使用到的例程、线程等概念。

例程(Subroutine)

例程的概念类似于函数,但含义更为丰富一些。例程是某个系统对外提供的功能接口或服务的集合。比如操作系统的API、服务等就是例程;C语言运行时提供的标准库函数等也是例程。Pthreads库提供的一套线程相关的API也属于例程。通俗的理解,一个子例程就是一次子函数调用,只不过相对一般函数,例程的通用性和相对独立性都比较强。

协程(Coroutine)

协程,意思就是“协作的例程”(co-operative routines),最早由Melvin Conway在1963年提出并实现。跟主流程序语言中的线程不一样,线程实现的系统称之为抢占式多任务系统,而协程实现的多任务系统是协作式多任务系统。线程由于缺乏yield语义,所以运行过程中不可避免需要调度,休眠挂起,上下文切换等系统开销,还需要小心使用同步机制保证多线程正常运行。而协程的调度是程序自行管理的,不需要同步机制,协程之间的切换也只涉及到控制权的交换,相比较线程来说是非常轻便的。

协程与例程的区别

通俗的理解,一个子例程就是一次子函数调用,那么实际上协程就是类似于函数一样的程序组件。它们的重要区别在于,通常而言,例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,也可以从上一个返回点继续执行,也就是说协程提供了 yield / resume的语义特性,即协程在执行过程中可以暂停,转而去执行其他的协程,同时可以在未来某个时刻点返回到上次暂停的地方继续往下执行。协程的最大威力也就在于此,比如利用协程的这种能力,我们可以轻易的实现想都不敢想的同步代码异步执行。再比如采用协程,我们也可以很容易的实现某种业务的状态机,而且可读性和可维护性大大的提高。

协程另外一个重要的特点就是:协程是作用在用户态,操作系统内核对于协程是毫无感知的,这样一来,协程的创建就类似于普通对象的创建,非常轻量级,从而使你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。可以想象一下,如果是在一个进程里面创建数十万个线程,结果该是怎样可怕。

进程、线程和协程
进程拥有自己独立的堆和栈,是系统资源管理的最小单位,进程由操作系统调度。
线程拥有自己独立的栈,共享堆,不共享栈,是系统调度的最小单位线程亦由操作系统调度。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示的调度,且协程的切换完全在用户态进行。

协程和线程的区别是:协程由于是程序完全自行管理协程的切换,极大的减少了进程/线程上下文的切换,避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。总体简而言之,本质上协程就是用户空间下的线程。

协程的实现库
Lua, Go等语言原生支持协程
Java依赖第三方库,例如最为著名的协程开源库Kilim
C标准库里的函数setjmp和longjmp可以用来实现一种协程。不幸的是,setjmp和longjmp的相当地难以实现。另外一种广为使用的C语言协程非标准库有 ucontext,网上绝大多数 C 协程库也是基于 ucontext 组件实现的。

### FreeRTOS 中协程的使用方法 #### 协程简介 FreeRTOS中的协程允许在同一任务内并发执行多个逻辑流。这些协程共享同一个上下文环境,因此可以直接访问相同的全局变量而不会引发数据竞争问题[^2]。 #### 创建和启动协程 为了创建并运行一个协程,在FreeRTOS中通常需要调用`xCoRoutineCreate()`函数来初始化一个新的协程实例,并指定其入口点函数。下面展示了一个简单的例子: ```c // 定义协程处理程序 void vCoroutineFunction( void *pvParameters ) { // 这里放置协程要做的工作... } int main(void) { // 启动第一个协程 xCoRoutineHandle_t xFirstCoroutine; xFirstCoroutine = xCoRoutineCreate(vCoroutineFunction, tskIDLE_PRIORITY, 0); // ...其他代码... return 0; } ``` #### 协程间的通信机制 当不同的任务下产生的协程间需互相传递消息时,则应采用由FreeRTOS提供的专用队列接口来进行安全的数据交换。需要注意的是这种类型的队列仅适用于协程之间的通讯;对于跨线程协程的情况则不适用。 ```c // 声明用于两个协程之间发送整数的消息队列 QueueHandle_t xQueue; // 初始化队列 xQueue = xQueueCreate(10, sizeof(int)); if (xQueue != NULL) { // 发送者协程向队列写入数值 int valueToSend = 42; xQueueSendToBack(xQueue, &valueToSend, portMAX_DELAY); // 接收者协程从队列读取数值 int receivedValue; if (xQueueReceive(xQueue, &receivedValue, portMAX_DELAY)) { printf("Received %d\n", receivedValue); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值