C++11实现的协程库,支持Win,Linux,Mac。
Fork Form https://github.com/mfichman/coro/commit/2d597a7ebe08bc28d91b98c942be17eb224b8853
C++ 协程的消息还是挺少的,补充一份。
协同程序(coroutine)简称协程
参考Lua中协同程序的介绍
http://www.runoob.com/lua/lua-coroutine.html
协程类,用于封装函数。一个协程只能包含一个函数,在执行期间的任何时刻可暂停和恢复。每个协程分配CORO_STACK_SIZE(1M)的内存大小。
class Coroutine : public std::enable_shared_from_this {
Coroutine(F func); // 构造函数,参数是一个函数,作为绑定函数
void start() throw(); // 执行绑定函数
内部 func_(); // 执行绑定的函数
event_->notifyAll();
void exit(); //当协程完成执行时,此函数运行。
内部event_->notifyAll();
main()->swap();
void swap(); // 将运行权给其它协程,当前正在执行的协程会挂起。
void yield(); // 挂起coroutine,将coroutine设置为挂起状态。RUNNING状态切换为RUNNABLE状态,下次循环会继续运行
void block(); // 阻止当前协同程序,直到发生某些I/O事件。 协程会在明确安排之前不得重新安排。RUNNING状态切换为BLOCKED状态
内部hub()->blocked_++;
void unblock(); // 解除阻止
内部hub()->blocked_--;
void wait(); // 阻止当前协同程序,直到发生某些事件。 协程不会被重新安排,直到明确安排。BLOCKED状态切换为RUNNABLE状态
内部hub()->waiting_++;
void notify(); // 在事件发生时取消阻止协同程序。
内部hub()->waiting_--;
// 部分成员变量
Ptr event_; // 信号
}
这个状态的过程比较的重要!
1、NEW --> RUNNING --> EXITED
2、RUNNING --> BLOCKED --> RUNNABLE --> RUNNING --> EXITED
3、WAITING --> RUNNABLE --> RUNNING --> EXITED
Coroutine::Coroutine(); // 初始化状态为RUNNING状态
Coroutine::~Coroutine(): // 切换为DELETED状态
void Coroutine::wait(); // RUNNING切换为WAITING状态
void Coroutine::notify(); // WAITING切换为RUNNABLE状态
void Coroutine::swap(); // 当前RUNNABLE切换为RUNNING;NEW切换为RUNNING;BLOCKED切换为RUNNING。最重要的函数,控制协程的中断,切换。
void Coroutine::exit(); // RUNNING切换为EXITED状态
void Coroutine::yield(); // RUNNING切换为RUNNABLE状态
void Coroutine::block(); // RUNNING切换为BLOCKED状态
void Coroutine::unblock(); // BLOCKED切换为RUNNABLE状态
每个协程分配CORO_STACK_SIZE(1M)的内存大小,保存到成员变量
Stack stack_;,所分配的内存会在Coroutine析构函数执行后释放。
if defined(_WIN32)
struct StackFrame {
void* fs8; // 栈顶
void* fs4; // 栈低
void* fs0; // Root-level SEH handler
void* rdi;
void* rsi;
void* rdx;
void* rcx;
void* rbx;
void* rax;
void* rbp;
void* returnAddr; // coroStart() stack frame here
};
stackPointer_ // 保存初始化的信息地址,未被调用。
Coroutine析构的时候释放内存。
协程的调用过程是单线程的,Event的控制是通过改变协程的状态来控制的。
void notifyAll(); // 通知所有协程运行,添加到std::vector容器中
void wait(); // 等待协程信号。实际是将协程的RUNNING切换为WAITING状态并挂起,调用其他的协程。
Hub类管理所有coroutines,events和I/O。
等待的事件(通道,I/O等)发出完成信号,在执行调用。
被定义为一个静态变量,通过coro::run()调用。
void quiesce(); // 遍历runnable_协程容器,更新协程的状态(void Coroutine::swap()),将RUNNABLE状态的协程保存到runnable_容器。
void poll(); // 轮询I/O事件。
void Hub::run(); // 循环运行,每次取一个协程
// 添加函数到协程容器
coro::start(baz);
// 挂起,RUNNING状态切换为RUNNABLE状态
coro::yield();
// 函数中调用,用于定时中断,中断时间到,继续执行
coro::sleep(coro::Time::millisec(1000));
// 执行协程容器
coro::run();
#include "coro/Common.hpp"
#include "coro/Coroutine.hpp"
#include "coro/Hub.hpp"
void bar() {
for (auto i = 0; i < 2; ++i) {
coro::sleep(coro::Time::millisec(1000));
std::cout << "barrrrrr" << std::endl;
}
}
void baz() {
for (auto i = 0; i < 20; ++i) {
coro::sleep(coro::Time::millisec(100));
std::cout << "baz" << std::endl;
}
}
int main() {
auto cbaz = coro::start(baz);
auto cbar = coro::start(bar);
coro::run();
return 0;
}
#include
#include
int main() {
auto event = coro::Event();
auto trigger = false;
auto notifier = coro::start([&]() {
printf("notified\n");
trigger = true;
event.notifyAll(); // 切换所有WAITING状态的协程为RUNNABLE状态
});
auto waiter = coro::start([&]() {
printf("waiting\n");
event.wait([&]() { return trigger; }); // 等待信号
printf("done\n");
});
coro::run();
return 0;
}
#include
#include
int main() {
auto counter = 0;
auto one = coro::start([&]{
coro::yield(); // 挂起,RUNNING切换为RUNNABLE状态。恢复的时候继续运行下去
assert(counter==0);
counter++;
std::cout << "one func" << counter << std::endl;
});
auto two = coro::start([&]{
one->join(); // two状态有RUNNING改为WAITING;one状态由RUNNABLE改为RUNNING。
assert(counter==1);
std::cout <<"two func" << counter << std::endl;
});
coro::run(); //
return 0;
}
使用这个类,开发者可以决定是否执行协程函数。
Selector局部变量析构函数中会将协程的状态由RUNNING切换为WAITING。Selector中可以保持多个协程对象。
#include
#include
using namespace coro;
Ptr e1(new Event);
Ptr e2(new Event);
Ptr e3(new Event);
void publisher() {
e1->notifyAll(); // 通知执行
e2->notifyAll(); // 通知执行
}
void consumer() {
int count = 2;
while (count > 0) {
coro::Selector() // 绑定信号和协程对象
.on(e1, [&]() { count--; std::cout << "e1" << std::endl; })
.on(e2, [&]() { count--; std::cout << "e2" << std::endl; })
.on(e3, [&]() { std::cout << "e3" << std::endl; });
}
}
int main() {
auto b = coro::start(consumer);
auto a = coro::start(publisher);
coro::run();
return 0;
}
https://github.com/wanttobeno/libcoro.git