如何向C++协程传递值?可行方案及示例问询
调用者向C++协程传递值的方法解答
首先明确:你无法直接在调用者中获取协程内部创建的MyAwaiter对象——因为co_await MyAwaiter{false}创建的是协程栈上的局部临时对象,调用者没有权限访问协程栈的私有内存,协程也没有暴露该对象的引用接口。
下面提供两种可行的传值方案,附最小可运行示例:
方案一:通过Promise对象传递数据
Promise是协程与调用者之间的标准交互桥梁,我们可以在promise中添加数据存储成员,调用者修改promise的数据,协程从promise中读取。
示例代码
#include <coroutine> #include <iostream> #include <string> struct ReturnObject { struct promise_type { // 存储调用者传递给协程的数据 std::string input_data_; // 标记是否有新数据待读取 bool has_new_data_ = false; ReturnObject get_return_object() { return ReturnObject{ .h_ = std::coroutine_handle<promise_type>::from_promise(*this) }; } // 初始挂起,让调用者有机会先设置数据 std::suspend_always initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void unhandled_exception() {} }; std::coroutine_handle<promise_type> h_; operator std::coroutine_handle<promise_type>() const { return h_; } }; // 自定义Awaiter,从Promise读取数据 struct DataAwaiter { ReturnObject::promise_type& promise_; bool await_ready() const noexcept { // 无新数据时挂起,等待调用者触发 return promise_.has_new_data_; } void await_suspend(std::coroutine_handle<>) const noexcept {} std::string await_resume() noexcept { // 返回数据并重置标记 promise_.has_new_data_ = false; return promise_.input_data_; } }; ReturnObject counter() { for (unsigned i = 0;; ++i) { std::cout << "协程迭代: i = " << i << std::endl; // 通过co_promise获取当前协程的promise对象 std::string ret = co_await DataAwaiter{co_promise}; std::cout << "协程收到数据: " << ret << std::endl; } } int main() { auto h = counter(); auto& promise = h.promise(); for (int i = 0; i < 3; ++i) { std::cout << "\n调用者准备传递数据" << std::endl; // 设置要传递给协程的数据 promise.input_data_ = "来自调用者的消息 " + std::to_string(i+1); promise.has_new_data_ = true; // 恢复协程执行 h(); } h.destroy(); }
方案二:让Awaiter持有外部共享数据源
将Awaiter设计为引用外部可访问的共享数据结构,调用者修改该结构,协程通过Awaiter读取数据。
示例代码
#include <coroutine> #include <iostream> #include <string> #include <memory> // 共享数据结构,用于调用者和协程之间传递数据 struct SharedData { std::string value; bool ready = false; }; struct ReturnObject { struct promise_type { ReturnObject get_return_object() { return ReturnObject{ .h_ = std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_always initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void unhandled_exception() {} }; std::coroutine_handle<promise_type> h_; operator std::coroutine_handle<promise_type>() const { return h_; } }; // 关联共享数据的Awaiter struct SharedAwaiter { std::shared_ptr<SharedData> data_; bool await_ready() const noexcept { return data_->ready; } void await_suspend(std::coroutine_handle<>) const noexcept {} std::string await_resume() noexcept { data_->ready = false; return data_->value; } }; ReturnObject counter(std::shared_ptr<SharedData> shared_data) { for (unsigned i = 0;; ++i) { std::cout << "协程迭代: i = " << i << std::endl; std::string ret = co_await SharedAwaiter{shared_data}; std::cout << "协程收到数据: " << ret << std::endl; } } int main() { auto shared_data = std::make_shared<SharedData>(); auto h = counter(shared_data); for (int i = 0; i < 3; ++i) { std::cout << "\n调用者准备传递数据" << std::endl; shared_data->value = "共享数据消息 " + std::to_string(i+1); shared_data->ready = true; // 恢复协程执行 h(); } h.destroy(); }
总结
- 你最初的思路(修改awaiter内部值传值)的核心问题是无法访问协程内部的局部awaiter对象,但通过让awaiter关联外部共享数据(方案二),可以实现类似逻辑。
- 方案一(通过Promise)是C++协程的常规传值方式,因为Promise本身就是为协程与调用者交互设计的标准入口。
内容的提问来源于stack exchange,提问作者Klaus
相关产品推荐
相关产品推荐

