本篇文章我们来讲述一下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代码实例:
cpp
#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()
方法来进行挂起和恢复操作。- 协程函数本身必须是异步上下文(比如异步任务、生成器)或者包含了异步操作。
代码实例:
cpp
#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() 方法和v
oid 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()
: 返回异步操作结果的值。
代码实例:
cpp
#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