## 目录 - [概述](#概述) - [核心特性](#核心特性) - [架构设计](#架构设计) - [API接口详解](#api接口详解) - [配置选项](#配置选项) - [使用指南](#使用指南) - [高级功能](#高级功能) - [错误处理](#错误处理) - [性能优化](#性能优化) - [平台支持](#平台支持) - [应用场景](#应用场景) ## 概述 协程模块是一种轻量级的用户态线程管理机制,在程序开发中扮演着重要角色,主要用于资源受限的嵌入式设备、网络编程、异步IO、实时数据处理等需要高效并发的场景。 相比传统线程具有更低的资源消耗(无需内核态切换)和更快的上下文切换速度,通过协程模块,开发者能够实现高效的任务切换和并发执行,从而提升程序的性能和响应速度。 **coroutine** 是一个高性能、轻量级的C语言协程库,采用非对称有栈协程设计。该库提供了完整的协程生命周期管理,支持多任务调度、定时器管理和事件同步机制,提供简洁的创建、调度与同步API接口,可无缝集成到嵌入式系统、服务器程序等多种环境中。并且移植起来也比较简单,只需要在目标平台上编译并链接该模块即可(已支持主流的芯片内核架构)。 ### 设计理念 - **简单易用**:提供直观的API接口 - **移植方便**:移植所需资源依赖少 - **高效性能**:低开销的上下文切换 - **稳定可靠**:错误处理和资源管理 ## 核心特性 ### 1. 架构特性 - **非对称有栈协程**:每个协程拥有独立的栈空间 - **多调度器支持**:可配置多个独立的协程调度器 - **混合内存管理**:支持静态预分配和动态内存管理 - **跨平台兼容**:支持x86、x64、ARM、MIPS等多种CPU架构(尚未完全测试完) ### 2. 协程状态管理 #### 协程调度器状态定义 ```c #define COSCHEDULER_STATE_INTI (0) // 初始化状态 #define COSCHEDULER_STATE_EXIT (1) // 退出状态 #define COSCHEDULER_STATE_START (2) // 启动状态 #define COSCHEDULER_STATE_RUNNING (3) // 运行状态 #define COSCHEDULER_STATE_SCHEDULE (4) // 调度状态 ``` #### 协程任务状态定义 ```c #define COTASK_STATE_INTI (0) // 初始化状态 #define COTASK_STATE_READY (1) // 就绪状态 #define COTASK_STATE_RUNNING (2) // 运行状态 #define COTASK_STATE_SUSPEND (3) // 挂起状态 #define COTASK_STATE_DELETED (4) // 删除状态 ``` ### 3. 内存管理配置 #### 静态资源限制配置 ```c #define COROUTINE_SCHEDULER_NUMBER 1 // 调度器数量 #define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // 静态任务最大数量 #define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // 静态定时器最大数量 #define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // 静态栈最大数量 #define COROUTINE_STACK_DEFAULT_SIZE 10240 // 默认栈大小 ``` ## 架构设计 ### 1. 整体架构 ``` +----------------------------------------------------+ | Architecture | +------------------------------------+---------------+ | | +---------+ | | +--------+ +--------+ | | CoTimer | | | | | | | | +---------+ | | | | CoEvent | | CoEvent +---------+ | | | CoTask |<=======>| CoTask |<=======>| CoTimer | | | | | | | | +---------+ | | | | | | | +---------+ | | +--------+ +--------+ | | CoTimer | | +------------------------------------+ +---------+ | | CoScheduler | +----------------------------------------------------+ ``` ### 2. 协程上下文切换机制 - 使用setjmp/longjmp实现快速上下文保存和恢复 - 每个协程维护独立的栈空间和环境 - 支持协程挂起、恢复和删除操作 ## API接口详解 ### 1. 调度器管理接口 #### CoScheduler_Init - 初始化协程调度器 **函数原型:** ```c #define CoScheduler_Init(CoSchedulerId, tick, tickInterval, ...) ``` **函数说明:** 初始化指定的协程调度器,设置时钟函数和时钟间隔。此函数必须在调用任何其他协程函数之前执行。 套用 `int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara);` 函数,提供更多的初始化参数配置。 **参数详解:** - `CoSchedulerId` **[必需]**:调度器ID,范围0到(COROUTINE_SCHEDULER_NUMBER-1) - `tick` **[必需]**:时钟函数指针,用于获取当前时间戳 - `tickInterval` **[必需]**:时钟间隔,表示每个tick对应的纳秒数 - `lock` **[可选]**:锁函数指针,用于多线程环境下的资源保护 - `unlock` **[可选]**:解锁函数指针,用于多线程环境下的资源释放 - `malloc` **[可选]**:内存分配函数指针 - `free` **[可选]**:内存释放函数指针 **返回值:** - `COROUTINE_E_OK` (0):初始化成功 - `COROUTINE_E_INVALID_PARAMETER` (-1):无效参数 - `COROUTINE_E_INVALID_TICK` (-2):无效时钟函数 - `COROUTINE_E_INVALID_TICK_INTERVAL` (-3):无效时钟间隔 - `COROUTINE_E_INVALID_LOCK` (-4):无效锁函数 - `COROUTINE_E_INVALID_MHOOK` (-5):无效内存钩子函数 **使用示例:** ```c // 基本使用:使用微秒时钟,1000us间隔 CoScheduler_Init(0, GetTimerUsec, 1000); // 多线程支持:带锁函数 CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock); // 完整配置:带内存管理函数 CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock, .malloc=malloc, .free=free ); ``` #### CoScheduler_Start - 启动协程调度器 **函数原型:** ```c int CoScheduler_Start(uint32_t CoSchedulerId); ``` **函数说明:** 启动指定的协程调度器,开始执行协程任务调度。 **参数:** - `CoSchedulerId`:调度器ID **返回值:** - 0:启动成功 - 错误码:启动失败 **使用流程:** ```c // 完整的调度器启动流程 CoScheduler_Init(0, GetTimerUsec, 1000); testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest)); CoScheduler_Start(0); ``` #### CoScheduler_Exit - 退出协程调度器 **函数原型:** ```c int CoScheduler_Exit(uint32_t CoSchedulerId); ``` **函数说明:** 退出指定的协程调度器,停止所有协程任务并清理资源。 **参数:** - `CoSchedulerId`:调度器ID **返回值:** - `COROUTINE_E_OK`:退出成功 ### 2. 协程任务管理接口 #### CoTask_Create - 创建协程任务 **函数原型:** ```c #define CoTask_Create(entry, ...) ``` **函数说明:** 创建一个新的协程任务,可以指定栈空间、参数和调度器。 套用 `CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara);` 函数,提供更多的初始化参数配置。 **参数详解:** - `entry` **[必需]**:协程入口函数指针,类型为`void (*)(void*)` - `pStack` **[可选]**:栈空间地址,如果为NULL则自动分配 - `stackSize` **[可选]**:栈大小,未指定时使用默认值 - `arg` **[可选]**:传递给协程的参数指针 - `schedulerId` **[可选]**:调度器ID,负值表示自动分配 **返回值:** - `CoTask_t`:成功创建的协程任务句柄 - `NULL`:创建失败 **使用示例:** ```c // 使用默认参数创建协程 CoTask_t testCoroutine = CoTask_Create(test); // 指定栈空间创建协程 CoTask_t testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest)); // 指定栈大小创建协程 CoTask_t testCoroutine = CoTask_Create(test, .stackSize=4096); // 带参数创建协程 int arg = 4096; CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg); ``` #### CoTask_Delete - 删除协程任务 **函数原型:** ```c int CoTask_Delete(CoTask_t CoTask); ``` **函数说明:** 删除指定的协程任务,释放相关资源。 **参数:** - `CoTask`:要删除的协程任务句柄 **返回值:** - 0:删除成功 - `COROUTINE_E_INVALID_PARAMETER`:无效参数 #### CoTask_Self - 获取当前协程任务 **函数原型:** ```c CoTask_t CoTask_Self(void); ``` **函数说明:** 获取当前正在运行的协程任务句柄。 **返回值:** - `CoTask_t`:当前协程任务句柄 - `NULL`:不在协程上下文中 #### CoTask_SchedulerId - 获取协程调度器ID **函数原型:** ```c int CoTask_SchedulerId(void); ``` **函数说明:** 获取当前协程任务所属的调度器ID。 **返回值:** - 调度器ID:0到(COROUTINE_SCHEDULER_NUMBER-1) ### 3. 协程等待机制接口 #### CoTask_Wait - 协程等待函数 **函数原型:** ```c #define CoTask_Wait(...) ``` **函数说明:** 使当前协程任务等待指定的事件或超时。 套用 `uint32_t CoTask_WaitP(CoTaskWaitPara *pPara);` 函数,提供更多的等待参数配置。 **参数详解:** - `pEvent` **[可选]**:等待的事件指针 - `ms` **[可选]**:等待的毫秒数 - `tick` **[可选]**:等待的tick数 **返回值:** - `uint32_t`:触发的事件标志位 **使用示例:** ```c void *test(void *arg) { while (1) { // 放弃调度器访问权,类似yield CoTask_Wait(); // 等待1000ms CoTask_Wait(.ms=1000); // 等待事件发生 uint32_t evs = CoTask_Wait(.pEvent=&g_Event); if (evs & 0x01) { printf("event 0x01 triggered\n"); } // 组合等待:事件+超时 evs = CoTask_Wait(.pEvent=&g_Event, .ms=5000); } } ``` 套用 `CoTask_Wait` 可以形成以下常用方法: ```c #define CoTask_WaitMs(m) CoTask_Wait(.ms=m) #define CoTask_WaitTick(t) CoTask_Wait(.tick=t) #define CoTask_WaitEvent(e) CoTask_Wait(.pEvent=e) #define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m) #define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t) ``` ### 4. 定时器管理接口 #### CoTimer_Create - 创建协程定时器 **函数原型:** ```c #define CoTimer_Create(entry, ...) ``` **函数说明:** 创建一个周期性的协程定时器。 套用 `CoTimer_t CoTimer_CreateP(CoTimerEntry_t entry, CoTimerCreatePara *pPara);` 函数,提供更多的初始化参数配置。 **参数详解:** - `entry` **[必需]**:定时器入口函数 - `ms` **[可选]**:毫秒间隔 - `tick` **[可选]**:tick间隔 **返回值:** - `CoTimer_t`:成功创建的定时器句柄 - `NULL`:创建失败 **使用示例:** ```c // 创建100ms间隔的定时器 CoTimer_t timer = CoTimer_Create(timer_entry, .ms=100); ``` #### CoTimer_Delete - 删除协程定时器 **函数原型:** ```c void CoTimer_Delete(CoTimer_t Timer); ``` **函数说明:** 删除指定的协程定时器。 **参数:** - `Timer`:要删除的定时器句柄 #### CoTimer_Self - 获取当前定时器 **函数原型:** ```c CoTimer_t CoTimer_Self(void); ``` **函数说明:** 获取当前正在运行的协程定时器句柄。 **返回值:** - `CoTimer_t`:当前定时器句柄 - `NULL`:不在定时器上下文中 ### 5. 事件同步接口 #### CoEvent_Init - 初始化事件 **函数原型:** ```c void CoEvent_Init(CoEvent *pEvent); ``` **函数说明:** 初始化协程事件,准备用于协程间同步。 **参数:** - `pEvent`:事件指针 **使用示例:** ```c CoEvent_Init(&g_Event); ``` 此方法为运行时调用,静态初始化可以直接赋值为 `COEVENT_STATIC_VALUE`。 ```c CoEvent g_Event = COEVENT_STATIC_VALUE; ``` #### CoEvent_Notify - 通知事件 **函数原型:** ```c void CoEvent_Notify(CoEvent *pEvent, uint32_t evs); ``` **函数说明:** 通知指定的事件,唤醒等待该事件的协程任务。 **参数详解:** - `pEvent`:事件指针 - `evs`:事件标志位,支持多事件同时通知 **使用示例:** ```c // 通知单个事件 CoEvent_Notify(&g_Event, 0x01); // 同时通知多个事件 CoEvent_Notify(&g_Event, 0x01 | 0x02 | 0x04); ``` ### 6. 监控统计接口 #### CoTask_StackMaxUsed - 获取协程栈最大使用量 **函数原型:** ```c size_t CoTask_StackMaxUsed(CoTask_t CoTask); ``` **函数说明:** 获取指定协程任务栈的最大使用量。 **参数:** - `CoTask`:协程任务句柄 **返回值:** - `size_t`:栈最大使用量(字节) #### CoTask_StackCurUsed - 获取协程栈当前使用量 **函数原型:** ```c size_t CoTask_StackCurUsed(CoTask_t CoTask); ``` **函数说明:** 获取指定协程任务栈的当前使用量。 **参数:** - `CoTask`:协程任务句柄 **返回值:** - `size_t`:栈当前使用量(字节) #### CoScheduler_CurLoad - 获取当前负载 **函数原型:** ```c uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId); ``` **函数说明:** 获取指定调度器的当前负载。 **返回值:** - `uint16_t`:当前负载百分比(0-10000,表示0.00%-100.00%) #### CoScheduler_MaxLoad - 获取最大历史负载 **函数原型:** ```c uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId); ``` **函数说明:** 获取指定调度器的历史最大负载。 **返回值:** - `uint16_t`:最大负载百分比 ### 7. 统计计数接口 #### CoScheduler_TaskCount - 获取协程任务数量 **函数原型:** ```c int CoScheduler_TaskCount(uint32_t CoSchedulerId); ``` **函数说明:** 获取指定调度器中的协程任务数量。 **参数:** - `CoSchedulerId`:调度器ID **返回值:** - `int`:协程任务数量 #### CoScheduler_TimerCount - 获取定时器数量 **函数原型:** ```c int CoScheduler_TimerCount(uint32_t CoSchedulerId); ``` **函数说明:** 获取指定调度器中的协程定时器数量。 **参数:** - `CoSchedulerId`:调度器ID **返回值:** - `int`:定时器数量 ## 配置选项 ### 编译时配置 (coroutine_cfg.h) **基本配置:** ```c // 调度器配置 #define COROUTINE_SCHEDULER_NUMBER 1 // 调度器数量 // 静态资源限制 #define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // 静态任务最大数量 #define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // 静态定时器最大数量 #define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // 静态栈最大数量 // 栈配置 #define COROUTINE_STACK_DEFAULT_SIZE 10240 // 默认栈大小 ``` **功能开关:** ```c // 栈使用量计算 #define COROUTINE_ENABLE_STACK_CALCULATE 1 // 启用栈使用量计算 // 负载计算 #define COROUTINE_ENABLE_LOADING_CALCULATE 1 // 启用负载计算 // 调试支持 #define COROUTINE_ENABLE_DEBUG 1 // 启用调试功能 ``` ## 使用指南 ### 1. 基本使用流程 #### 初始化阶段 ```c #include "coroutine.h" // 定义时钟函数 uint64_t GetTimerUsec(void) { // 返回微秒级时间戳 return ...; } int main(void) { // 初始化调度器0,使用微秒时钟,1000us间隔 CoScheduler_Init(0, GetTimerUsec, 1000); ``` #### 协程定义 ```c // 协程任务函数 void *test_task(void *arg) { int *p_count = (int*)arg; while (1) { // 协程任务逻辑 (*p_count)++; // 主动让出CPU CoTask_Wait(); } return NULL; } ``` #### 创建和启动 ```c // 创建协程任务 int count = 0; CoTask_t testCoroutine = CoTask_Create(test_task, .arg=&count); ``` ### 2. 高级使用模式 #### 事件驱动模式 ```c void *event_driven_task(void *arg) { while (1) { // 等待事件 uint32_t evs = CoTask_Wait(.pEvent=&g_Event); if (evs & 0x01) { // 处理事件0x01 handle_event_01(); } if (evs & 0x02) { // 处理事件0x02 handle_event_02(); } } } ``` #### 定时器模式 ```c void *timer_task(void *arg) { while (1) { // 每100ms执行一次 CoTask_Wait(.ms=100); // 定时器逻辑 periodic_work(); } } ``` ## 高级功能 ### 1. 栈使用量计算 启用 `COROUTINE_ENABLE_STACK_CALCULATE` 后,可以监控协程栈的使用情况: ```c // 获取协程栈最大使用量 size_t maxUsed = CoTask_StackMaxUsed(CoTask); // 获取协程栈当前使用量 size_t curUsed = CoTask_StackCurUsed(CoTask); ``` ### 2. 负载计算 启用 `COROUTINE_ENABLE_LOADING_CALCULATE` 后,可以计算调度器的负载: ```c // 获取当前负载 uint16_t curLoad = CoScheduler_CurLoad(CoSchedulerId); // 获取最大历史负载 uint16_t maxLoad = CoScheduler_MaxLoad(CoSchedulerId); ``` ### 3. 性能监控 ```c // 监控协程调度性能 void monitor_scheduler_performance(void) { uint16_t curLoad = CoScheduler_CurLoad(0); uint16_t maxLoad = CoScheduler_MaxLoad(0); if (curLoad > 8000) { // 80%负载警告 printf("Warning: Scheduler load is high: %d.%02d%%\n", curLoad/100, curLoad%100); } ``` ## 错误处理 ### 错误码定义 ```c #define COROUTINE_E_OK (0) // 成功 #define COROUTINE_E_INVALID_PARAMETER (-1) // 无效参数 #define COROUTINE_E_INVALID_TICK (-2) // 无效时钟函数 #define COROUTINE_E_INVALID_TICK_INTERVAL (-3) // 无效时钟间隔 #define COROUTINE_E_INVALID_LOCK (-4) // 无效锁函数 #define COROUTINE_E_INVALID_MHOOK (-5) // 无效内存钩子函数 ``` ## 性能优化 ### 1. 上下文切换优化 - 使用setjmp/longjmp替代完整的上下文保存 - 最小化寄存器保存和恢复操作 ### 2. 内存管理优化 - 静态预分配减少动态内存分配 - 栈空间复用机制 ## 平台支持 该库通过内联汇编实现了跨平台的栈指针操作: - **x86/x64**:使用esp/rsp寄存器 - **ARM**:使用sp寄存器 - **MIPS**:使用sp寄存器 - **RISC-V**:使用sp寄存器 - **PowerPC**:使用r1寄存器 ### 平台特定实现 ```c // x86架构实现 #if defined(__i386__) #define COROUTINE_GET_STACK_POINTER(p) \ __asm__ __volatile__("movl %%esp, %0" : "=r"(p)) ``` ## 应用场景 ### 1. 嵌入式系统 - 实时任务调度 - 低功耗设备管理 - 传感器数据处理 ### 2. 网络编程 - 异步I/O处理 - 连接池管理 - 协议栈实现 ### 3. 游戏开发 - 游戏对象更新 - AI行为调度 - 动画系统管理 ### 4. 物联网应用 - 设备通信协议 - 数据处理流水线 - 远程控制接口 ## 总结 **coroutine** 协程库是一个功能强大、性能优异的C语言协程解决方案。它提供了: 1. **完整的协程生命周期管理** 2. **高效的多任务调度机制** 3. **灵活的定时器和事件管理** 4. **完善的错误处理和监控功能**