C++ 并发核心:std::promise、std::future、std::async 超详细全解

这三个是 C++11 引入的线程间通信、异步任务、获取线程返回值 的核心工具,解决了传统多线程无法直接获取返回值、无法安全传递异常、线程同步麻烦的问题。

我会用最通俗的语言 + 完整代码示例 + 核心原理,从基础到进阶讲透,保证你能彻底理解。


先搞懂核心定位:它们是干嘛的?

一句话总结三者关系:

  • std::async启动一个异步任务(相当于自动创建线程 / 复用线程执行函数)
  • std::future未来的结果 (用来获取异步任务的返回值 / 异常)
  • std::promise承诺一个结果 (用来手动设置值 / 异常,再把结果交给 future)

简单比喻:

  • promise = 厨师,负责做好菜(设置值)
  • future = 取餐号,负责取菜(获取值)
  • async = 外卖平台,自动派厨师做菜,你只需要拿取餐号等结果

一、std::future:未来的结果(核心载体)

1. 是什么?

future 是一个模板类 ,用来等待异步操作的结果 。它本身不能直接存值 ,只能从 promiseasync 那里获取结果

2. 核心方法

方法 作用
get() 阻塞等待,直到结果就绪,然后返回值(只能调用 1 次)
wait() 阻塞等待结果就绪,但不返回值
wait_for(timeout) 等待指定时间,超时就返回,不卡死
wait_until(time) 等待到指定时间点
valid() 判断 future 是否还有效

3. 关键特性

  • get() 只能调用一次,调用后 future 失效
  • 没结果时调用 get()阻塞当前线程,直到结果到来
  • 可以安全接收异步线程抛出的异常(传统线程做不到)

二、std::promise:手动承诺一个结果

1. 是什么?

promise 也是模板类,作用是:手动在某个线程中设置一个值 / 异常 ,然后把结果交给关联的 future,让另一个线程获取。

它是手动线程通信的工具。

2. 核心方法

方法 作用
get_future() 获取和当前 promise 绑定的 future
set_value(val) 设置结果值(只能调 1 次)
set_exception(e) 设置异常(线程间传递异常)

3. 完整示例:线程 A 给线程 B 传值

复制代码
#include <iostream>
#include <thread>
#include <future>
using namespace std;

// 子线程函数:接收 promise,负责设置值
void worker(promise<int>& p) {
    cout << "子线程:正在计算...\n";
    this_thread::sleep_for(chrono::seconds(2));  // 模拟耗时
    
    // ✅ 设置结果,交给 future
    p.set_value(1024);
    cout << "子线程:已设置结果 1024\n";
}

int main() {
    // 1. 创建 promise(承诺返回 int)
    promise<int> p;
    
    // 2. 获取绑定的 future
    future<int> f = p.get_future();

    // 3. 启动子线程,把 promise 传进去
    thread t(worker, ref(p));

    cout << "主线程:等待子线程结果...\n";
    // 4. 阻塞等待,获取结果
    int res = f.get();
    cout << "主线程:获取到结果 = " << res << endl;

    t.join();
    return 0;
}

4. 进阶:线程间传递异常

promise 最大的优势之一:子线程的异常可以抛给主线程,传统线程做不到!

复制代码
void worker(promise<int>& p) {
    try {
        throw runtime_error("子线程出错啦!");
    } catch (...) {
        // ✅ 把异常设置给 promise
        p.set_exception(current_exception());
    }
}

int main() {
    promise<int> p;
    future<int> f = p.get_future();
    thread t(worker, ref(p));

    try {
        f.get();  // 主线程 get() 时会收到异常
    } catch (exception& e) {
        cout << "主线程捕获异常:" << e.what() << endl;
    }

    t.join();
    return 0;
}

三、std::async:最简单的异步任务(最常用)

1. 是什么?

async 是一个函数模板自动创建 / 复用线程 执行函数,直接返回 future,不用手动管线程、promise。

它是日常开发最推荐的异步方式。

2. 两种启动策略(必懂)

策略 含义
launch::async 立即创建新线程执行任务(强制异步)
launch::deferred 延迟执行 ,直到调用 get()/wait() 才在当前线程执行(同步)
默认 `async deferred`,系统自动选择

3. 完整示例:获取异步函数返回值

复制代码
#include <iostream>
#include <future>
using namespace std;

// 异步执行的函数
int calc(int x, int y) {
    cout << "异步任务:计算中...\n";
    this_thread::sleep_for(chrono::seconds(2));
    return x + y;
}

int main() {
    // ✅ 启动异步任务,立即创建线程执行 calc(10,20)
    future<int> f = async(launch::async, calc, 10, 20);

    cout << "主线程:做自己的事...\n";

    // 阻塞等待结果
    int res = f.get();
    cout << "异步结果:" << res << endl;

    return 0;
}

4. 优势

  • 不用写 thread、不用写 promise
  • 直接获取函数返回值
  • 直接捕获函数异常
  • 代码极简、安全

四、三者关系与底层原理(彻底吃透)

1. 数据通道:共享状态

三者底层都依赖一个叫 ** 共享状态(shared state)** 的堆内存:

  • promise → 写共享状态
  • future → 读共享状态
  • async → 内部封装了 promise,自动写结果

2. 完整关系图

复制代码
异步任务/线程 → std::promise(set_value)→ 共享状态 → std::future(get)→ 主线程
std::async(自动执行)→ 内部 promise → 共享状态 → std::future → 主线程

3. 核心区别

工具 用途 手动 / 自动
future 获取结果 被动读取
promise 手动设置结果 手动线程通信
async 启动异步任务 自动创建线程 + 自动返回 future

五、高频坑点(一定要避)

  1. future::get() 只能调用一次第二次调用会直接崩溃,因为结果已经被取走了。

  2. async 如果不接收返回值,会同步阻塞错误写法:

    复制代码
    async(launch::async, calc);  // 临时 future 立即析构,阻塞主线程

    正确写法:必须用 future 接收。

  3. deferred 策略不会创建线程 它是延迟同步执行,不是异步,别用错。

  4. promisefuture 是一一绑定的 一个 promise 只能绑定一个 future,不能复用。

  5. 线程间传递异常必须用 set_exception 子线程直接 throw,主线程收不到,必须通过 promise 传递。


六、完整综合示例(覆盖所有知识点)

复制代码
#include <iostream>
#include <future>
using namespace std;

// 异步函数
int task(int a) {
    this_thread::sleep_for(chrono::seconds(1));
    if (a < 0) throw invalid_argument("参数不能为负");
    return a * 10;
}

int main() {
    // ========== 1. async 异步任务 ==========
    future<int> f1 = async(launch::async, task, 10);
    cout << "async 结果:" << f1.get() << endl;

    // ========== 2. promise + future 手动通信 ==========
    promise<int> p;
    future<int> f2 = p.get_future();

    thread t([&]() {
        try {
            p.set_value(task(20));
        } catch (...) {
            p.set_exception(current_exception());
        }
    });

    try {
        cout << "promise 结果:" << f2.get() << endl;
    } catch (exception& e) {
        cout << "捕获异常:" << e.what() << endl;
    }

    t.join();
    return 0;
}

总结

  1. std::future获取异步结果get() 阻塞取值,只能取一次
  2. std::promise手动设置结果 / 异常,用于手动线程通信
  3. std::async自动启动异步任务,直接返回 future,最简单常用
  4. 底层靠共享状态 通信,支持线程间安全传值 + 传异常
  5. 日常开发优先用 async,需要手动控制线程用 promise+future

std::future:获取异步结果,获取promise提前手动设置好的值或者async异步执行任务返回的结果

相关推荐
EverestVIP2 小时前
C++ 成员函数的指针
c++
俺不要写代码2 小时前
线程启动、结束,创建线程多法、join,detach,线程的移动语义
服务器·开发语言·网络·c++
雾岛听蓝2 小时前
Qt Widget控件属性详解
开发语言·经验分享·笔记·qt
好家伙VCC2 小时前
# 发散创新:用 Rust实现高性能物理引擎的底层架构设计与实战在游戏开发、虚拟仿真和机器人控
java·开发语言·python·rust·机器人
boonya2 小时前
一文读懂MCP:AI连接万物的“USB-C接口”
c语言·开发语言·人工智能
liliangcsdn2 小时前
多轮对话长上下文-向量检索和混合召回示例
开发语言·数据库·人工智能·python
思麟呀2 小时前
应用层协议HTTP
linux·服务器·网络·c++·网络协议·http
leoZ2312 小时前
金仓老旧项目改造-10
开发语言·前端·人工智能·python·金仓
故事和你912 小时前
洛谷-数据结构1-1-线性表2
开发语言·数据结构·算法·动态规划·图论