本篇文章我们来讲述一下C++协程
协程(Coroutine)是一种能够挂起个恢复的函数过程 是一种轻量级的并发编程方式,也称为用户级线程。它与传统的线程(Thread)相比,具有更低的开销和更高的执行效率。 协程通常运用在异步调用中。
同步和异步 (拓展):同步是指线程要同时执行 如果没有两者没有同步 则需要线程A 等待线程B 或者主线程等待子线程 而异步编程就不需要线程的等待 但是也要注意线程争夺的问题
协程要讲清楚非常的抽象和复杂 我们直接从实际入手
代码实例:
大家看完以上代码结果可能会有一点懵 这是什么? 这是怎么回事?下面 让我们来分析一下代码:
大家观察这段代码就知道 main函数创建了一个进程 进程里面创建了一个主线程 然后执行每个函数就是子线程 先进入bar()函数 先执行call bar 然后执行before bar 经过挂起点然后挂起 这时候一个线程跳出了bar函数 到main里面 另一个线程执行fool函数 fool函数执行完以后 再回到bar 函数里面继续执行 这就是本代码的大概思路
下面我们来介绍一下 co_return 和co_await
co_return :
co_return
是 C++20 中引入的关键字,用于在协程中返回结果或结束协程。它用于替代return
关键字,在协程函数中表示返回值,并触发协程的完成。
co_return代码实例:
#include <iostream> #include <experimental/coroutine> std::experimental::coroutine_handle<> myCoroutine; void myTask() { std::cout << "Starting coroutine..." << std::endl; myCoroutine.resume(); // 启动协程 std::cout << "Resuming execution..." << std::endl; } struct MyAwaitable { bool await_ready() const { return false; } void await_suspend(std::experimental::coroutine_handle<> handle) const { myCoroutine = handle; // 将当前协程保存起来 } void await_resume() const {} }; MyAwaitable asyncFunc() { std::cout << "Suspending execution..." << std::endl; co_await MyAwaitable{}; // 挂起协程,等待恢复 std::cout << "Resumed execution..." << std::endl; } int main() { myTask(); asyncFunc().await_resume(); return 0; }
在这个示例中,
co_await
表达式会挂起asyncFunc()
协程的执行,然后将控制权交还给myTask()
协程。当我们调用myCoroutine.resume()
时,asyncFunc()
的执行恢复,并继续执行后面的语句。
co_await介绍:
co_await
是 C++20 中引入的关键字,用于在协程中挂起当前的执行,并等待某个操作完成或者恢复执行。它是协程内部使用的一种语法,用于表示异步操作的等待。在一个可暂停函数(协程)中,当遇到
co_await
表达式时,会发生以下几个步骤:
- 暂停当前协程的执行,并保存当前状态。
- 将控制权返回给调用方(如上层协程或者普通函数)。
- 在某个事件发生或者异步操作完成后,恢复之前保存的状态并继续执行。
具体来说,在使用
co_await
时需要满足两个条件:
- 表达式必须是一个可暂停的类型(也称为 Awaitable 类型),它要么定义了
bool await_ready()
方法来判断是否可以直接返回结果,要么定义了void await_suspend(std::coroutine_handle<>)
方法和void await_resume()
方法来进行挂起和恢复操作。- 协程函数本身必须是异步上下文(比如异步任务、生成器)或者包含了异步操作。
代码实例:
#include <iostream> #include <experimental/coroutine> struct MyAwaitable { bool await_ready() const { return false; } void await_suspend(std::experimental::coroutine_handle<> handle) const { std::cout << "Suspending coroutine..." << std::endl; handle.resume(); // 恢复协程的执行 } void await_resume() const {} }; std::experimental::suspend_always asyncFunc() { std::cout << "Starting coroutine..." << std::endl; co_await MyAwaitable{}; // 使用 co_await 挂起协程 std::cout << "Resuming execution..." << std::endl; } int main() { auto coro = asyncFunc(); coro.resume(); // 启动协程 return 0; }
代码总结:在这个示例中,
MyAwaitable
是一个自定义的可暂停类型,它定义了bool await_ready()
方法和void await_suspend(std::coroutine_handle<>)
方法来控制协程的挂起和恢复。当我们调用co_await MyAwaitable{}
时,协程会被挂起,并且打印出相应的消息。然后通过handle.resume()
来恢复协程的执行。
co_await实现对象:
co_await
来实现协程等待一个对象时,该对象需要满足特定的条件和接口。在 C++ 中,需要实现以下几个关键的部分:
- 实现
awaitable
类型:这是一个自定义的类型,表示可以被协程等待的对象。它需要定义await_ready()
、await_suspend()
和await_resume()
这三个成员函数。
await_ready()
: 返回一个 bool 值,表示对象是否已经准备好(即不需要暂停协程)。如果对象已经可用,则返回 true;否则返回 false。await_suspend()
: 返回一个指定异步操作完成后应该如何恢复协程执行的 awaiter 类型。await_resume()
: 返回异步操作结果的值。
代码实例:
#include <iostream> #include <future> #include <experimental/coroutine> struct Awaitable { std::future<int> fut; bool await_ready() { return fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } void await_suspend(std::experimental::coroutine_handle<> handle) { fut.then([handle](std::future<int> f) mutable { // 异步操作完成后恢复协程执行 handle.resume(); }); } int await_resume() { return fut.get(); } }; Awaitable makeAsyncRequest() { std::promise<int> p; auto fut = p.get_future(); // 模拟异步操作 std::thread([&p]() mutable { std::this_thread::sleep_for(std::chrono::seconds(2)); p.set_value(42); }).detach(); return Awaitable{std::move(fut)}; } std::experimental::suspend_always task() { auto result = co_await makeAsyncRequest(); // 等待异步操作完成,并获取结果 std::cout << "Result: " << result << std::endl; } int main() { auto coro = task(); coro.resume(); // 启动协程 return 0; }
总结:协程是应用于异步编程的一种方法
co_await函数用于当前的协程的挂起 这样可以更深层次的满足异步编程 要注意co_await函数的使用 co_return是用来返回结果和结束协程
好了 本篇内容就到这里 这篇文章可能有些难度 大家慢慢理解
在这里小编想向大家推荐一个课程:https://xxetb.xetslk.com/s/2PjJ3T