c++的std::coroutine_handle是什么? (手动控制协程)
技术百科
裘德小鎮的故事
发布时间:2026-01-13
浏览: 次 std::coroutine_handle 是协程的轻量级控制句柄,用于 resume、destroy 或查询已挂起协程;必须从协程内部或 promise 获取,不可默认构造,且 T 必须匹配 promise 类型,生命周期需与协程帧严格对齐。
std::coroutine_handle 是协程的“遥控器”
它不是协程本身,而是一个轻量级句柄,用来手动 resume、destroy 或查询一个已挂起的协程状态。你拿到它,就等于拿到了对那个协程执行流的控制权——但前提是协程已经挂起(比如在 co_await 后暂停),且你持有其合法的 std::coroutine_handle 实例。
怎么拿到有效的 std::coroutine_handle?
不能凭空构造,必须从协程内部或其 promise 对象中获取。常见路径:
- 在
promise_type::get_return_object()里调用std::coroutine_handle返回 handle::from_promise(*this) - 在
await_suspend()回调中,参数std::coroutine_handle就是当前协程的 handle - 通过
std::coroutine_handle手动转换地址(危险,仅限底层调度器等场景)::from_address(ptr)
错误做法:std::coroutine_handle 或默认构造后直接 resume() —— 这是未初始化的空 handle,调用 resume()/destroy() 会未定义行为(通常 crash)。
resume() 和 destroy() 的调用时机很关键
这两个操作都要求 handle 非空且指向一个**尚未被销毁**的协程帧。典型陷阱:
- 协程已运行结束(即执行完函数体或被 co_return/co_yield 后自动销毁),再调用
resume()→ UB - 多次调用
destroy()→ UB(协程帧只能销毁一次) - 在
await_suspend()返回false后,又手动resume()→ 协程可能已被调度器立即恢复,重复 resume 会崩溃
安全做法:总是先检查 h && h.done() == false 再 resume();destroy() 前确保不会再访问该 handle。
为什么类型模板参数不能乱写?
std::coroutine_handle 中的 T 必须与协程 promise 类型一致(通常是 promise_type)。例如:
struct MyPromise { /* ... */ };
MyCoroutine my_coro() { co_return; } // 返回类型隐含 MyPromise
// 正确:
std::coroutine_handle h = /* ... */;
// 错误:
std::coroutine_handle hv = h; // 编译失败:不能隐式转换
std::coroutine_handle hi = h; // 编译失败:类型不匹配
只有 std::coroutine_handle 是通用“无类型”句柄,可用于跨 promise 类型传递(比如调度器统一管理),但它无法访问 promise 成员,且必须由 from_address() 构造,不能直接从 typed
handle 转换。
真正难的不是调用 resume(),而是保证 handle 生命周期和协程帧生命周期严格对齐——稍有错位,就是悬垂指针或双重释放。别指望编译器帮你查这个。
# ai
# 这是
# 帮你
# 但它
# 已被
# 这两个
# 仅限
# 稍有
# 对象
# c++
# 隐式转换
# void
# 指针
# 为什么
# 无类型
# this
# 挂起
# 句柄
# promise
# 会再
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Mac的访达(Finder)怎么用_Mac文件管理
- php修改数据怎么改富文本_update更新htm
- 如何使用正则表达式提取以编号开头、后接多个注解的逻
- php485函数执行慢怎么优化_php485性能提
- Win11如何卸载OneDrive_Win11卸载
- Win11怎么恢复旧版开始菜单_通过软件还原Win
- Win11怎么查看硬盘型号_Windows 11检
- Win10怎样设置多显示器_Win10多显示器扩展
- 如何使用Golang处理静态文件缓存_提高页面加载
- Win10怎样卸载iTunes_Win10卸载iT
- Win10电脑怎么设置休眠快捷键_Windows1
- 如何使用Golang实现错误包装与传递_Golan
- 如何使用Golang指针与结构体结合_修改结构体内
- PHP主流架构如何做单元测试_工具与流程【详解】
- Go 语言标准库为何不提供泛型 Contains
- 如何在Golang中处理模块包路径变化_Golan
- Windows如何使用BitLocker To G
- c++中的std::conjunction和std
- 如何使用Golang捕获测试日志_Golang t
- c++如何打印函数堆栈信息_c++ backtra
- MAC怎么在照片中添加水印_MAC自带编辑工具文字
- Avalonia如何实现跨窗口通信 Avaloni
- mac怎么分屏_MAC双屏显示与分屏操作技巧【指南
- LINUX怎么进行文本内容搜索_Linux gre
- Win11怎么查看已连接wifi密码 Win11查
- Python列表推导式与字典推导式教程_简化代码高
- Python 模块的 __name__ 属性如何由
- Win11搜索栏无法输入_解决Win11开始菜单搜
- Windows10怎样设置家长控制_Windows
- c++如何实现一个高性能的环形队列(Ring Bu
- Win10如何卸载自带Edge_Win10彻底卸载
- c++中的CRTP是什么 c++奇异递归模板模式【
- Windows音频驱动无声音原因解析_声卡驱动错误
- Windows如何拦截2345弹窗广告_Windo
- 如何在Golang中使用闭包_封装变量与函数作用域
- Windows10怎么卸载预装软件_Windows
- Windows10怎么查看硬件信息_Windows
- c++中如何计算坐标系中两点间距离_c++勾股定理
- php怎么下载安装后测试是否成功_简单脚本验证方法
- Windows10系统怎么查看CPU核心数_Win
- Win11如何添加/删除输入法 Win11切换中英
- Win11文件扩展名怎么显示 Win11查看文件后
- Windows10如何更改任务栏高度_Win10解
- Win11怎么忘记WiFi网络_Win11删除已保
- 如何高效获取循环末次生成的 NumPy 数组最后一
- Windows电脑如何进入安全模式?(多种按键方法
- Win11怎么更改计算机名_Windows11系统
- 如何在Golang中实现邮件发送功能_Golang
- 如何将竖排文本文件转换为横排字符串
- Go语言中slice追加操作的底层共享机制详解

QQ客服