include: co/co.h.
#Coroutine APIs
v3.0 移除了co::init
,co::exit
,co::stop
。
#go
1. void go(Closure* cb);
2. template<typename F>
void go(F&& f);
3. template<typename F, typename P>
void go(F&& f, P&& p);
4. template<typename F, typename T, typename P>
void go(F&& f, T* t, P&& p);
-
此函数用于创建协程,与创建线程类似,需要指定一个协程函数。
-
1, 参数 cb 指向一个 Closure 对象,协程启动后会调用 Closure 中的
run()
方法。 -
2-4, 将传入的参数打包成一个 Closure,然后调用 1。
-
2, 参数 f 是任意可调用的对象,只要能调用
f()
或(*f)()
就行。 -
3, 参数 f 是任意可调用的对象,只要能调用
f(p)
,(*f)(p)
或(p->*f)()
就行。 -
4, 参数 f 是类中带一个参数的方法
void T::f(P)
,参数 t 是T
类型的指针,参数 p 是方法 f 的参数。 -
实际测试发现,创建
std::function
类型的对象开销较大,应尽量少用。 -
示例
go(f); // void f();
go(f, 7); // void f(int);
go(&T::f, &o); // void T::f(); T o;
go(&T::f, &o, 3); // void T::f(int); T o;
// lambda
go([](){
LOG << "hello co";
});
// std::function
std::function<void()> x(std::bind(f, 7));
go(x);
go(&x); // Ensure that x is alive when the coroutine is running.
#DEF_main
这个宏用于定义 main 函数,并将 main 函数中的代码也放到协程中运行。DEF_main 内部已经调用 flag::parse() 解析命令行参数,用户无需再次调用。
- 示例
DEF_main(argc, argv) {
go([](){
LOG << "hello world";
});
co::sleep(100);
return 0;
}
#———————————
#co::coroutine
void* coroutine();
- 返回当前的 coroutine 指针,若在非协程中调用此函数,则返回值是 NULL。
- 此函数的返回值,可作为 co::resume() 的参数,用于唤醒协程。
#co::resume
void resume(void* p);
- 唤醒指定的协程,参数
p
是 co::coroutine() 的返回值。 - 此函数是线程安全的,可在任意地方调用。
#co::yield
void yield();
- 挂起当前协程,必须在协程中调用。
- 此函数配合 co::coroutine() 与 co::resume(),可以手动控制协程的调度,详情参考 test/yield.cc。
#———————————
#co::coroutine_id
int coroutine_id();
- 返回当前协程的 id,在非协程中调用时,返回值是 -1。
#co::main_sched
MainSched* main_sched();
- 此函数用于将主线程变成调度线程。
- 用户获取
MainSched
指针后,必须在主线程中调用其loop()
方法。
#include "co/co.h"
#include "co/cout.h"
int main(int argc, char** argv) {
flag::parse(argc, argv);
co::print("main thread id: ", co::thread_id());
auto s = co::main_sched();
for (int i = 0; i < 8; ++i) {
go([]{
co::print("thread: ", co::thread_id(), " sched: ", co::sched_id());
});
}
s->loop(); // loop forever
return 0; // fake return value
}
#co::next_sched
Sched* next_sched();
-
返回指向下一个
Sched
的指针。 -
go(…) 实际上等价于
co::next_sched()->go(...)
。 -
示例
// 创建在同一个线程中运行的协程
auto s = co::next_sched();
s->go(f1);
s->go(f2);
v3.0.1 中将co::next_scheduler
重命名为co::next_sched
。
#co::sched
Sched* sched();
- 返回指向当前协程调度器的指针,调度器与调度线程是一一对应的,如果当前线程不是调度线程,返回值是 NULL。
v3.0.1 中将co::scheduler
重命名为co::sched
。
#co::scheds
const co::vector<Sched*>& scheds();
- 返回协程调度器列表的引用。
v3.0.1 中将co::schedulers
重命名为co::scheds
。
#co::sched_id
int sched_id();
- 返回当前协程调度器的 id,这个值是 0 到
co::sched_num()-1
之间的值。如果当前线程不是调度线程,返回值是 -1。
v3.0.1 中将co::scheduler_id
重命名为co::sched_id
。
#co::sched_num
int sched_num();
-
返回协程调度器的数量,此函数常用于实现一些协程安全的数据结构。
-
示例
co::vector<T> v(co::sched_num(), 0);
void f() {
// get object for the current scheduler
auto& t = v[co::sched_id()];
}
go(f);
v3.0.1 中将co::scheduler_num
重命名为co::sched_num
。
#co::stop_scheds
void stop_scheds();
- 停止所有协程调度器,退出所有调度线程。
#代码示例
// print sched id and coroutine id every 3 seconds
#include "co/co.h"
#include "co/cout.h"
void f() {
while (true) {
co::print("s: ", co::sched_id(), " c: ", co::coroutine_id());
co::sleep(3000);
}
}
int main(int argc, char** argv) {
flag::parse(argc, argv);
for (int i = 0; i < 32; ++i) go(f);
while (true) sleep::sec(1024);
return 0;
}
#———————————
#co::sleep
void sleep(uint32 ms);
- 让当前协程睡一会儿,参数 ms 是时间,单位是毫秒。
- 此函数一般在协程中调用,在非协程中调用相当于
sleep::ms(ms)
。
#co::timeout
bool timeout();
- 判断之前的 IO 操作是否超时。用户在调用
co::recv()
等带超时时间的函数后,可以调用此函数判断是否超时。 - 此函数必须在协程中调用。