# coroutine **Repository Path**: dennis-kk/coroutine ## Basic Information - **Project Name**: coroutine - **Description**: C++轻量级协程库 - **Primary Language**: C++ - **License**: BSD-2-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 8 - **Forks**: 1 - **Created**: 2019-11-20 - **Last Updated**: 2024-11-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # coroutine 轻量级跨平台协程库 ## 平台 Windows(基于Fiber实现), CentOS(基于ucontext_t实现) ## C++版本 C++17
1. Windows: cygwin+clang,Visual Studio 2019 2. Linux: gcc/g++ 64位 ## 线程关联 每一个线程都会维护一个独立的协程集合,不同线程内的协程调度是彼此隔离的,不同线程的协程调度互不影响,不会出现如下情况: ``` 1. 线程A内的协程被调度器切换到线程B内的协程 2. 线程A内的协程与线程B内的协程通过消息队列通信,跨线程的协程通信现有实现不支持,但是用户可以自己封装支持 ``` 不同线程内的协程通过用户数据产生的关联需要用户自行保证数据竞争带来的安全性问题 ## 编译 ``` + src + -- coroutine.h 头文件 + -- coro_call.h 协程调用基础库头文件 + -- linux linux实现 + -- windows Windows实现 + -- test 单元测试 + -- detail 数据结构,定时器,协程调用基础库实现 + -- main.cpp 单元测试入口 ``` 可以直接包含源代码在已有代码中直接使用 ## 协程状态 协程包含3个状态: 1. 就绪 READY
已经准备好运行,或者处于READY状态,协程入口函数执行完后会切换到DEAD状态,协程出让CPU会切换到SUSPEND状态 2. 挂起 SUSPEND
因为某种原因出让了CPU 3. 死亡 DEAD
死亡状态,即将被销毁 ``` _______________ / \ \/ | READY -------> SUSPEND | | \----->DEAD<-----/ ``` ![协程切换](https://images.gitee.com/uploads/images/2020/0116/135819_ea8e8645_467198.png "屏幕截图.png") ## 协程挂起状态 1. 等待消息(MSG_WAIT)
等待消息到来,譬如调用了coro_pop_wait会让当前协程处于此状态 2. 休眠 (SLEEP)
调用coro_sleep会让当前协程处于此状态 3. 出让CPU (YIELD)
调用coro_yield或者coro_resume会让当前协程处于此状态 ## 调度 1. 存在3个协程链表分别对应:READY,SUSPEND,DEAD三种状态 2. 协程在链表内的顺序即优先级,新切换到这三个状态的协程会被放到链表的末尾 3. 使用coro_resume,coro_push会改变调度优先级,被唤醒的协程会被马上切换为READY状态并执行 4. coro_sched方法会按顺序启动READY链表内的协程 5. 有一个全局指针维持当前正在运行的协程 ## 方法 1. coro_spawn 建立一个协程
协程建立后处于就绪状态,没有立即运行,可以通过多种方式让这个就绪协程运行 2. coro_start 建立并运行一个协程
建立并立即运行协程 3. coro_yield 出让当前协程的CPU 4. coro_sched 运行一次调度器 5. coro_resume 恢复某个处于挂起状态或就绪状态的协程的运行 6. coro_close 关闭协程 7. coro_close_all 关闭所有协程 8. coro_id 返回当前协程ID 9. coro_shutdown 关闭协程库,清理所有资源 10. coro_push 推送数据到其他协程 11. coro_pop 尝试获取数据从消息队列 12. coro_pop_wait 等待队列数据 13. coro_sleep 协程睡眠指定毫秒 14. coro_quit 退出当前协程 15. coro_cancel 取消协程运行,对应协程将抛出异常 ## 主要方法说明 ### coro_spawn 建立一个协程并处于READY状态(没有运行),可以使用coro_resume让协程开始运行,也可以通过coro_sched来运行 ``` auto c1 = coro_spawn(nullptr); coro_resume(c1); ``` coro_spawn第一个参数是类型为std::functioin的协程入口函数,第二个参数为传递给入口函数的参数,类型为void*,默认为nullptr ### coro_start 建立一个协程并立即运行 ``` auto c1 = coro_start(nullptr); ``` ### coro_yield 出让当前CPU并切换到其他READY状态的协程,同时协程将被切换到SUSPEND状态,如果指定目标协程(处于SUSPEND状态)则直接唤醒这个协程 ``` auto c1 = coro_spawn([](void* ptr) { ... }); coro_yield(c1); ``` ``` auto c1 = coro_spawn([](void* ptr) { ... }); auto c2 = coro_spawn([](void* ptr) { coro_yield(c1); }); coro_resume(c2); ``` ### coro_sched 运行一次调度器,调度器将自动切换到某一个READY状态的协程并运行直到没有READY状态的协程为止,同时还会检查处于SUSPEND状态的协程是否可以被唤醒,如果可以被唤醒将立刻唤醒(切换到READY)状态并运行 ### coro_resume 当前协程将被切换到SUSPEND状态,如果目标协程处于SUSPEND状态,切换目标协程状态为READY并运行. coro_resume还可以在唤醒 目标协程的同时给它传递一个消息 ``` auto c1 = coro_spawn([](void* ptr) { auto msg = coro_pop(); ... }); coro_resume(c1, "hello world"); ```