在 C++20 中,协程(coroutines)是一个重磅新特性,它简化了异步编程的方式。你不再需要使用传统的回调函数、状态机或线程池来处理异步操作。通过协程,你可以像写同步代码一样写异步代码,同时保留异步执行的优势。
协程是一种特殊的函数,它可以在执行过程中暂停,并且能够在之后的某个时刻继续执行。与线程不同,协程并不会真正地“脱离”当前的线程,它只是让控制流从一个函数流转到另一个地方,然后再回来。这个过程是 轻量级 和 非阻塞 的。
co_await
:用于挂起协程并等待某个操作完成,类似于 await
在其他语言中的表现。co_return
:用于从协程中返回结果并结束协程的执行。coroutine_handle
是 C++ 协程中的一个非常重要的类型,它用来管理协程的生命周期和状态。通过它,你可以控制协程的执行、挂起和恢复。
coroutine_handle
的作用:在 C++ 协程中,每个协程都有一个 promise_type
结构体,它定义了协程的返回值和生命周期管理。coroutine_handle
则是与该 promise_type
类型关联的句柄,主要用于以下几个方面:
管理协程的生命周期:
coroutine_handle
是一个与特定协程实例关联的句柄,通过它可以管理协程的暂停、恢复和销毁。恢复协程执行:
coroutine_handle
可以恢复已挂起的协程执行。协程挂起时,它的状态会被保存,直到 resume()
被调用。销毁协程:
coroutine_handle
来销毁协程对象,释放其资源。coroutine_handle
的定义与用法:在协程中,promise_type
是协程返回的类型,它定义了协程的开始、结束以及如何处理异常等。而 coroutine_handle
是一个专门的句柄,负责管理协程的执行。它通过与 promise_type
结合,允许外部控制协程的流程。
struct promise_type {
MyTask get_return_object() {
return MyTask{handle_type::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::exit(1); }
};
using handle_type = std::coroutine_handle<promise_type>;
std::coroutine_handle
:是一个模板类,promise_type
是协程中的 promise
类型,协程的生命周期和状态通过它来管理。get_return_object()
:该方法返回协程对象,创建并返回一个 MyTask
对象,协程会通过 std::coroutine_handle
来控制。initial_suspend()
和 final_suspend()
:分别控制协程的初始挂起和最终挂起行为。#include
#include
#include
struct MyTask {
struct promise_type; // 声明 promise_type
using handle_type = std::coroutine_handle<promise_type>;
MyTask(handle_type h) : coro(h) {}
~MyTask() { coro.destroy(); }
handle_type coro;
};
struct MyTask::promise_type {
MyTask get_return_object() {
return MyTask{handle_type::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {
std::exit(1); // 如果发生异常,退出
}
};
MyTask my_coroutine() {
std::cout << "Start of coroutine\n";
co_await std::suspend_always{}; // 挂起协程
std::cout << "End of coroutine\n";
}
int main() {
auto task = my_coroutine(); // 调用协程
std::cout << "Before coroutine resume\n";
task.coro.resume(); // 恢复协程
std::cout << "After coroutine resume\n";
return 0;
}
Before coroutine resume
Start of coroutine
After coroutine resume
End of coroutine
coroutine_handle::resume()
:
resume()
恢复它。coroutine_handle::destroy()
:
destroy()
来销毁协程对象。coroutine_handle::from_promise(promise_type&)
:
promise_type
创建协程句柄。promise_type
是定义协程返回值的类型,它负责处理协程的结果。coroutine_handle
是 C++ 协程的核心,它帮助你管理协程的生命周期和状态,允许你暂停、恢复和销毁协程。promise_type
紧密配合的,promise_type
定义了协程的行为,而 coroutine_handle
则管理协程的执行。理解并熟练使用协程句柄将大大提升你编写高效异步代码的能力,值得深入掌握!
#include
#include
#include
struct MyTask {
struct promise_type; // 声明 promise_type
using handle_type = std::coroutine_handle<promise_type>;
MyTask(handle_type h) : coro(h) {}
~MyTask() { coro.destroy(); }
handle_type coro;
};
struct MyTask::promise_type {
MyTask get_return_object() {
return MyTask{handle_type::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; } // 初始挂起
std::suspend_never final_suspend() noexcept { return {}; } // 最终挂起
void return_void() {} // 协程返回
// 异常处理
void unhandled_exception() {
std::exit(1); // 如果发生异常,退出
}
};
MyTask my_coroutine() {
std::cout << "Start of coroutine\n";
co_await std::suspend_always{}; // 挂起协程
std::cout << "End of coroutine\n";
}
int main() {
auto task = my_coroutine(); // 调用协程
std::cout << "Before coroutine resume\n";
task.coro.resume(); // 恢复协程
std::cout << "After coroutine resume\n";
return 0;
}
MyTask
和 promise_type
promise_type
:是一个特殊结构体,协程的生命周期由它管理。get_return_object
创建并返回协程对象。co_await
:用于挂起协程,这里的 std::suspend_always{}
表示协程将在该点暂停,直到调用 resume()
恢复执行。co_await
后,协程会挂起,直到通过调用 coro.resume()
来恢复它的执行。initial_suspend()
和 final_suspend()
控制协程何时开始和结束。Before coroutine resume
Start of coroutine
After coroutine resume
End of coroutine
std::future
和 std::async
C++20 协程可以与标准库的异步功能(如 std::future
和 std::async
)结合使用,能够让协程变得更加易于使用。例如,使用 co_await
来等待 std::future
。
#include
#include
#include
std::future<int> async_task() {
co_return 42; // 协程返回一个值
}
int main() {
auto result = async_task();
std::cout << "Result from coroutine: " << result.get() << "\n";
return 0;
}
co_await
和 co_return
co_await
:协程挂起并等待某个操作(如异步任务的结果)。co_return
:返回协程的结果。std::suspend_always
和 std::suspend_never
std::suspend_always
:协程总是会挂起。std::suspend_never
:协程永远不会挂起,直接执行。异步 I/O 操作:
协程可以使得异步 I/O 操作变得像同步操作一样书写,避免回调地狱。
任务调度和并发:
在多任务并发处理时,协程提供了一种更加直观且易于管理的方式来切换任务,减少了线程的开销。
网络编程:
协程在网络请求处理等需要等待的场景中,能够极大简化代码结构,并提高性能。
C++20 协程将异步编程推向了一个全新的高度,它的优势在于:
std::future
)和其他异步库无缝配合,提升编程体验。虽然 C++ 协程的学习曲线稍微陡峭一些,但它带来的编程便利性无疑是值得掌握的!