简单的协程
#include <iostream> // 包含标准输入输出流头文件
#include <thread> // 包含线程支持头文件
#include <coroutine> // 包含协程支持头文件
#include <future> // 包含异步操作支持头文件
#include <chrono> // 包含时间库头文件
#include <functional> // 包含函数对象头文件// 定义一个名为 Result 的结构体
struct Result{// 定义一个 promise_type 结构体struct promise_type {// 返回一个 Result 对象Result get_return_object() { return {}; }// 定义协程的初始挂起点std::suspend_never initial_suspend() { return {}; }// 定义协程的最终挂起点std::suspend_never final_suspend() noexcept { return {}; }// 协程的返回值类型为 voidvoid return_void() {}// 未处理的异常处理函数void unhandled_exception() {}};
};// 定义一个全局的协程句柄
std::coroutine_handle<> coroutine_handle;// 定义一个可等待对象结构体
struct AWaitableObject
{// 默认构造函数AWaitableObject() {}// 定义 await_ready 函数,表示是否准备好bool await_ready() const { return false; }// 定义 await_resume 函数,表示恢复时的返回值int await_resume() { return 0; }// 定义 await_suspend 函数,表示挂起协程时的操作void await_suspend(std::coroutine_handle<> handle){// 保存协程句柄coroutine_handle = handle;}
};// 定义一个协程函数
Result CoroutineFunction()
{// 打印开始协程的信息std::cout << "start coroutine\n";// 等待可等待对象int ret = co_await AWaitableObject(); // 打印完成协程的信息std::cout << "finish coroutine\n";
}// 主函数
int main()
{// 打印开始的信息std::cout << "start \n"; // 调用协程函数auto coro = CoroutineFunction();// 打印协程 co_await 的信息std::cout << "coroutine co_await\n"; // 恢复协程coroutine_handle.resume();// 返回 0 表示程序正常结束return 0;
}
co_await
是 C++20 引入的一种新的操作符,用于支持协程的异步等待。co_await
操作符的使用需要等待一个可等待对象,该对象需要实现三个特定的成员函数或通过重载对应的操作符。这三个成员函数分别是 await_ready()
, await_suspend()
, 和 await_resume()
。我们来看一下在你的代码中 co_await AWaitableObject()
是如何工作的:
-
await_ready
:bool await_ready() const { return false; }
- 这个函数返回一个布尔值,表示这个对象是否已经准备好。如果返回
true
,协程将不会被挂起,直接继续执行后续代码。如果返回false
,协程将被挂起,直到这个对象准备好。 - 在你的代码中,
await_ready
总是返回false
,所以协程会被挂起。
- 这个函数返回一个布尔值,表示这个对象是否已经准备好。如果返回
-
await_suspend
:void await_suspend(std::coroutine_handle<> handle) {coroutine_handle = handle; }
- 这个函数在协程被挂起时被调用。它接受一个
std::coroutine_handle
作为参数,表示当前协程的句柄。 - 在你的代码中,它将协程句柄保存到全局变量
coroutine_handle
中。这允许你在以后手动恢复这个协程。
- 这个函数在协程被挂起时被调用。它接受一个
-
await_resume
:int await_resume() { return 0; }
- 这个函数在协程恢复时被调用。它的返回值将成为
co_await
表达式的结果。 - 在你的代码中,它返回
0
。
- 这个函数在协程恢复时被调用。它的返回值将成为
现在我们具体来看 co_await AWaitableObject();
在你的代码中的执行流程:
-
进入
CoroutineFunction
函数:std::cout << "start coroutine\n";
- 打印 “start coroutine”。
-
执行
co_await AWaitableObject()
:- 创建一个
AWaitableObject
对象。 - 调用
AWaitableObject
的await_ready
方法,返回false
,因此协程挂起。 - 调用
AWaitableObject
的await_suspend
方法,将协程句柄保存到全局变量coroutine_handle
中。 - 协程挂起,控制权返回到调用方
main
函数。
- 创建一个
-
回到
main
函数:std::cout << "coroutine co_await\n";
- 打印 “coroutine co_await”。
-
恢复协程:
coroutine_handle.resume();
- 手动恢复协程,调用
await_resume
方法,返回0
。
- 手动恢复协程,调用
-
继续执行
CoroutineFunction
:std::cout << "finish coroutine\n";
- 打印 “finish coroutine”。
整个过程展示了协程的挂起和恢复机制,通过 co_await
实现异步操作。AWaitableObject
作为一个可等待对象,实现了协程所需的三个成员函数,协调了协程的挂起和恢复。
多个任务
#include <chrono>
#include <coroutine>
#include <deque>
#include <iostream>
#include <windows.h>
std::deque<std::coroutine_handle<>> tasks;
// 简单的协程类
struct AsyncTask {struct promise_type {AsyncTask get_return_object() { return {}; }std::suspend_never initial_suspend() { return {}; }std::suspend_never final_suspend() noexcept { return {}; }void return_void() {}void unhandled_exception() {}};
};
struct AWaitableObject {int delay;AWaitableObject(int delay) : delay(delay) {}bool await_ready() const { return false; }int await_resume() { return 0; }void await_suspend(std::coroutine_handle<> handle) {tasks.push_back(handle);Sleep(delay);}
};
// 模拟异步任务1
AsyncTask task1() {co_await AWaitableObject(200);std::cout << "Task 1 completed" << std::endl;
}// 模拟异步任务2
AsyncTask task2() {co_await AWaitableObject(100);std::cout << "Task 2 completed" << std::endl;
}// 主函数
int main() {// 打印开始的信息std::cout << "main start \n";task1();task2();std::cout << "main continue\n";// 恢复协程while (!tasks.empty()) {auto task = tasks.front();tasks.pop_front();task.resume();}std::cout << "main completed" << std::endl;return 0;
}
推荐资料:
深入浅出c++协程