从使用角度解读c++20 协程示例
ww_250 人气:0协程长什么样子
网上一堆乱七八糟的定义,看的人云里雾里,毫无意义。下面从实战角度看看协程到底长什么样子。
首先,类比线程,线程是个函数。把这个函数交给 创建线程的api,然后这个函数就变成线程了。这个函数本身没有任何特殊的地方,就是普通函数。
- 相比于线程,协程也是个函数,不过协程函数比线程函数讲究多了。
- 它必须要有返回值,返回值的类型 还必须’内嵌’一个promise_type类型promise_type类型 还必须 至少包含几个特定的实现
返回值类型最简如下:
struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void unhandled_exception() noexcept {} task get_return_object() noexcept { return {}; } }; };
从表现形式上说,下面就是个最简协程函数:
task do_by_coroutine() {}
c++20的协程三板斧
co_await、co_return、co_yield。
这3个关键字是用来控制协程运行的,那么自然只能在协程函数里面使用。他们到底是用来干什么的?
co_return
最简单最好理解的。普通函数返回用return,协程函数返回用co_return,没什么稀奇的含义,很好理解。但是用起来又比较讲究。
如果协程函数返回’void’,那么promise_type类型需要对应加一个return_void实现
struct task { struct promise_type { ... void return_void() noexcept {} //for co_return void }; };
如果协程函数返回’值’,那么promise_type类型需要对应加一个return_value实现, 比如返回一个字符串,形参v就是返回的’值’
struct task { struct promise_type { ... void return_value(std::string&& v) noexcept {} //for co_return value }; };
co_yield
co_yield其实没必要去深入理解它,它其实是co_await的一个’变体糖’。co_yield expr 会被转化为 co_await promise.yield_value(expr),本质还是co_await。
同样co_yield用起来也比较讲究。挂起协程同时返回一个值,promise_type类型需要对应加一个yield_value实现,比如返回一个字符串,形参from就是返回的’值’
struct task { struct promise_type { ... std::suspend_always yield_value(std::string&& from) noexcept{ //for co_yield value value_ = std::move(from); return {}; } std::string value_; }; };
co_await
最后一个同时也是最讲究的关键字。
co_await expr,从这个expr必须可以得到awaitable对象。到底什么是awaitable?包含以下3个特定实现的就是awaitable,最简的awaitable定义如下:
struct awaitable { bool await_ready() noexcept { return false; } std::string await_resume() noexcept { return "123"; }; void await_suspend(std::coroutine_handle<> h) noexcept {}; };
最简单的使用方式:
auto value = co_await awaiter{};
上述语句怎么和awaitable的3个实现关联起来的?
- 首先调用await_ready,根据返回值来控制协程运行。
- 如果返回值false,则会调用await_suspend,挂起协程,形参h表示协程对象,可以用来控制协程。
- 如果返回值true,则会调用await_resume,返回"123"给value,不过await_ready通常为false,因为需要主动控制协程。
- 第2步中,挂起协程后,可以调用resume在合适的时机恢复协程运行,调用resume后,await_resume会被调用,返回"123"给value。
- 主要是步骤1->2->4,await_resume返回值也可以为空。
理解协程
协程函数必须要有返回值,且返回值类型必须符合特定要求,这个点比线程函数讲究多了。
协程三板斧关键字 也必须符合对应要求才可以使用。co_return对应return_void或者return_value,co_yield对应yield_value,co_await对应awaitable。
写点简单的示例代码,单纯从使用角度上来理解协程,其实就这么点东西。
加载全部内容