c++ std::future和std::promise c++线程间通信【教程】
技术百科
尼克
发布时间:2026-01-02
浏览: 次 std::future 和 std::promise 是 C++11 提供的线程安全异步值传递机制,用于单次结果传递;promise 设置值或异常(仅一次),future 通过 get() 获取(仅一次),二者通过共享状态关联,支持移动但不可拷贝。
std::future 和 std::promise 是 C++11 引入的一对配套工具,用于在线程间安全地传递单次结果值,适合“一个线程生产、另一个线程消费”的场景。它们不共享内存,也不需要手动加锁,本质是基于同步通道的异步值传递机制。
std::promise 负责设置结果值
每个 std::promise 对象关联一个共享状态(shared state),它只能被调用一次 se
t_value()、set_exception() 或 set_exception_at_thread_exit()。多次调用会抛出 std::future_error 异常。
- promise 必须在设置值前,把对应的 future 交给消费者线程(通常通过 move 语义转移)
- promise 对象本身可被移动,但不可拷贝;它的 shared state 是线程安全的
- 如果 promise 被销毁而未设置值,其 shared state 会以 std::future_error 异常结束
std::future 负责获取结果值
future 是 promise 的“读取端”,通过 get() 阻塞等待并取出值(或异常)。get() 只能调用一次,之后 future 失效(变为无效状态)。
- 调用 get() 会阻塞当前线程,直到 promise 设置了值或异常
- future 支持 wait()、wait_for()、wait_until() 等非阻塞等待方式,用于轮询或超时控制
- future 也可由 std::async、std::packaged_task 自动创建,不一定非要配对使用 promise
典型协作流程示例
以下是一个跨线程传递 int 值的最小可行代码:
#include#include #include int main() { std::promise p; std::future f = p.get_future(); // 获取关联 future std::thread t([&p]() { std::this_thread::sleep_for(std::chrono::seconds(1)); p.set_value(42); // 生产者设值 }); std::cout << "等待中..." << std::endl; int result = f.get(); // 消费者取值(阻塞) std::cout << "得到:" << result << std::endl; t.join(); }
注意:lambda 捕获 promise 时需用引用(&p),否则 set_value 作用于副本,主线程将永远阻塞。
常见陷阱与建议
- 避免复制 future 或 promise —— 它们都只支持移动语义
- 不要在 promise 析构前忘记 set_value;可用 std::optional + RAII 封装规避
- 若需多次通信,不要强行复用 future/promise;改用 std::queue + mutex 或 std::condition_variable
- 异常传播很自然:promise.set_exception(std::make_exception_ptr(...)),future.get() 会重新抛出
# ai
# 是一个
# 也不
# 都只
# 时需
# 会以
# 可由
# 作用于
# 工具
# 对象
# c++
# int
# stream
# 线程
# 异步
# red
# 封装
# 抛出
# ios
# Lambda
# 加锁
# 主线程
# 值传递
# 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; ?>
】
相关推荐
- Go 语言标准库为何不提供泛型切片的 Contai
- Windows怎样关闭开始菜单推荐广告_Windo
- 如何在Golang中编写端到端测试_Golang
- Windows10蓝屏SYSTEM_SERVICE
- Win11怎么设置开机密码_Windows11账户
- Win11如何关闭游戏模式 Win11禁用Xbox
- 如何在Golang中处理二进制数据_Golang
- Win11怎么关闭自动调节屏幕亮度_Windows
- 如何使用Golang recover捕获panic
- c++ std::atomic如何保证原子性 c+
- 如何使用Golang实现容器健康检查_监控和自动重
- 如何在 Go 应用中实现自动错误恢复与进程重启机制
- PythonDocker高级项目部署教程_多容器管
- Win11怎样安装微信开发者工具_Win11安装开
- Windows 11无法安全删除U盘提示设备正在使
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- 如何使用Golang table-driven f
- Mac怎么查看活动监视器_理解Mac进程和资源占用
- 如何在Golang中优化文件读写性能_使用缓冲和并
- php报错怎么查看_定位PHP致命错误与警告的方法
- 如何在Golang中验证模块完整性_Golangg
- 如何使用Golang benchmark测量函数延
- Python类装饰器使用_元编程解析【教程】
- c++ atoi和atof函数用法_c++字符数组
- Win11怎么开启远程桌面_Win11系统远程桌面
- Win11关机界面怎么改_Win11自定义关机画面
- Win11怎么解压RAR文件 Win11自带解压功
- Win11声音太小怎么办_Windows 11开启
- Win11怎么更改鼠标指针方案_Windows11
- 如何使用Golang实现微服务事件驱动_使用消息总
- Win11怎么设置桌面图标间距_Windows11
- 如何减少Golang内存碎片化_Golang内存分
- Win11怎么查看电脑配置_Win11硬件配置详细
- php修改数据怎么批量改状态_批量更新status
- Bpmn 2.0的XML文件怎么画流程图
- VSC怎样在VSC中调试PHPAPI_接口调试技巧
- Win11怎么设置按流量计费_Win11限制后台流
- Win10如何卸载WindowsDefender_
- C++中引用和指针有什么区别?(代码说明)
- Mac如何使用听写功能_Mac语音输入打字【效率技
- 如何在同包不同文件中正确引用 Go 结构体
- c++如何获取map中所有的键_C++遍历键值对提
- Win11怎样安装企业微信_Win11安装企业微信
- VSC怎么配置PHP的Xdebug_远程调试设置步
- 用lighttpd能运行php吗_lighttpd
- 如何使用Golang开发简单的聊天室消息存储_Go
- 如何在Golang中使用encoding/gob序
- C++中的std::shared_from_thi
- 如何使用Golang包导出规则_控制函数和变量可见
- Python列表推导式与字典推导式教程_简化代码高

QQ客服