协程
协程函数
若一个函数中出现了以下三个关键字之一,则编译器就知道这是一个协程函数
co_await
co_yield
co_return
并且,协程函数必须返回一个符合要求的协程对象,若有返回值,需要通过协程对象获得
协程对象
协程函数的返回值是自定义的一个协程对象
模板
通常需要内嵌一个名为promise_type的结构定义,内部需要实现一些函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <coroutine> struct MyCoroutine { struct promise_type { MyCoroutine get_return_object () { return MyCoroutine (); } std::suspend_never initial_suspend () { return {}; } std::suspend_never final_suspend () noexcept { return {}; } void return_void () {} void unhandled_exception () {} }; }; MyCoroutine coroFunc () { std::cout <<"hello world" << std::endl; co_return ; } int main () { MyCoroutine coro = coroFunc (); return 0 ; }
此时coroFunc刚开始执行就被挂起,MyCoroutine对象也没有实现任何协程,故后面的代码不会执行,稍微进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <coroutine> struct MyCoroutine { struct promise_type { MyCoroutine get_return_object () { return MyCoroutine (std::coroutine_handle<promise_type>::from_promise (*this )); } std::suspend_always initial_suspend () { return {}; } std::suspend_always final_suspend () noexcept { return {}; } void return_void () {} void unhandled_exception () {} }; MyCoroutine (std::coroutine_handle<promise_type> h) : handle (h) {} void resume () { if (handle) { handle.resume (); } } private : std::coroutine_handle<promise_type> handle; }; MyCoroutine coroFunc () { std::cout <<"hello world" << std::endl; co_return ; } int main () { MyCoroutine coro = coroFunc (); coro.resume (); return 0 ; }
返回值
若需要提供返回值,则需要将return_void改为return_value,并添加get函数存储并获取反返回值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> #include <coroutine> struct MyCoroutine { struct promise_type { MyCoroutine get_return_object () { return MyCoroutine (std::coroutine_handle<promise_type>::from_promise (*this )); } std::suspend_always initial_suspend () { return {}; } std::suspend_always final_suspend () noexcept { return {}; } void return_value (int v) {_value = v;} void unhandled_exception () {} public : int get () {return _value;} private : int _value; }; MyCoroutine (std::coroutine_handle<promise_type> h) : handle (h) {} int get () { handle.resume (); return handle.promise ().get (); } private : std::coroutine_handle<promise_type> handle; }; MyCoroutine coroFunc () { std::cout <<"hello world" << std::endl; co_return 666 ; } int main () { MyCoroutine coro = coroFunc (); int value = coro.get (); std::cout << "value= " << value << std::endl; return 0 ; }
co_yield
如果要使用co_yield,需要添加yield_value函数
由于co_yield不是函数执行的结尾,故需要返回一个可等待对象,并使用co_await对该对象进行等待,即
1 2 co_yield v;co_await promise.yield_value (v);
或者返回一个suspend_always对象,让程序挂起
1 auto yield_value (int v) { _value = v; return std::suspend_always{};}
为方便使用,还可以重载一下布尔运算符,通过调用handle的done函数来判断协程是否执行完毕
1 operator bool () {return !handle.done();}
在主函数中,就可以通过一个循环对协程执行进行挂起和继续操作,并获得每次的返回值
1 2 3 4 5 MyCoroutine coro = coroFunc (); while (coro){ int value = coro.get (); std::cout << "value= " << value << std::endl; }
应用:实现发生器(Generator)
一个斐波那契数列生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> #include <coroutine> struct MyCoroutine { struct promise_type { MyCoroutine get_return_object () { return MyCoroutine (std::coroutine_handle<promise_type>::from_promise (*this )); } std::suspend_always initial_suspend () { return {}; } std::suspend_always final_suspend () noexcept { return {}; } void return_value (int v) {_value = v;} auto yield_value (int v) { _value = v; return std::suspend_always{};} void unhandled_exception () {} public : int get () {return _value;} private : int _value; }; MyCoroutine (std::coroutine_handle<promise_type> h) : handle (h) {} operator bool () {return !handle.done();} int get () { handle.resume (); return handle.promise ().get (); } private : std::coroutine_handle<promise_type> handle; }; MyCoroutine fib () { int a = 0 , b = 1 , n = 40 ; co_yield a; co_yield b; while (n--){ int r = a+b; co_yield r; a = b; b = r; } co_return a+b; } int main () { MyCoroutine coro = fib (); while (coro){ int value = coro.get (); std::cout << "value= " << value << std::endl; } return 0 ; }
co_await
语法:co_await 表达式
表达式可以是可等待对象,重载co_await()运算符,也可以是一个promise类型的await_transform()函数,将表达式作为函数参数并返回可等待对象
可等待类型awaitable的定义如下:
1 2 3 4 5 6 struct awaitable { bool await_ready () ; void await_suspend (std::coroutine_handle<> h) ; auto await_resume () ; };
调用对象时,首先调用await_ready(),若返回值为false,则调用await_suspend()让程序挂起,当协程继续执行后,会接下来执行await_resume(),若返回值为true,则直接执行await_resume()
内置类型suspend_always中await_ready()返回false,其余两个函数什么都不做,作用是将程序挂起
内置类型suspend_never中await_ready()返回true,其余两个函数什么都不做
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <coroutine> #include <iostream> #include <thread> struct promise ;struct MyCoroutine : std::coroutine_handle<promise>{ using promise_type = ::promise; }; struct promise { MyCoroutine get_return_object () { return {MyCoroutine::from_promise (*this )}; } auto initial_suspend () { return std::suspend_always{}; } auto final_suspend () noexcept { return std::suspend_always{}; } void unhandled_exception () {} }; struct awaitable { bool await_ready () { std::cout << "await_ready called" << std::endl; return false ; } void await_suspend (std::coroutine_handle<> h) { std::cout << "await_suspend called" << std::endl; h.resume (); } auto await_resume () { std::cout << "await_resume called" << std::endl; return 666 ; } }; MyCoroutine coroFunc () { std::cout << "coroFunc started" << std::endl; co_await awaitable{}; std::cout << "coroFunc resumed" << std::endl; } int main () { MyCoroutine coro = coroFunc (); std::cout << "main started" << std::endl; coro.resume (); std::cout << "main finished" << std::endl; return 0 ; }
1 2 3 4 5 6 7 main started coroFunc started await_ready called await_suspend called await_resume called coroFunc resumed main finished
根据返回结果,证明了函数调用的顺序是ready->suspend->resume