set_value

在 C++ 的 std::promisestd::future 机制中,set_value 是相对于 set_exception 的另一面。

如果说 set_exception 是用来报告“任务失败/出错了”,那么 set_value 就是用来提交“任务成功/结果算好了”

它是 std::promise 类的一个成员函数,作用是将计算结果存入共享状态,并通知对应的 future:“数据准备好了,可以来取了。”


1. set_value 的三种形态

根据 std::promise<T> 模板参数 T 的不同,set_value 的用法略有区别:

A. 传递具体数据 (std::promise<int>, std::promise<string> 等)

这是最直观的用法。子线程算出了结果,通过 set_value 传回去。

// 场景:子线程计算 10 + 20
void worker(std::promise<int> prom) {
    int result = 10 + 20;
    // 【关键动作】提交结果
    prom.set_value(result); 
}
// 主线程:fut.get() 将会得到 30

B. 仅发送完成信号 (std::promise<void>)

这是您在之前的代码片段中看到的用法。 如果 Tvoid,说明我们不关心返回值,只关心“任务做完了没有”

void worker(std::promise<void> prom) {
    // 做一些耗时操作...
    doHeavyWork();
    
    // 【关键动作】不传参数,仅表示“我做完了”
    prom.set_value(); 
}
// 主线程:fut.get() 只是解除阻塞,不返回任何数据

C. 传递引用 (std::promise<T&>)

较少见,用于直接传递对象的引用。


2. 完整工作流对比

我们可以把 std::promise 看作一个快递员

  • set_value: 快递员把货物(正常结果)放进了快递柜。

  • set_exception: 快递员把损坏说明书(异常对象)放进了快递柜。

  • future.get(): 收件人(主线程)打开快递柜。如果里面是货,就拿走;如果里面是说明书,当场崩溃(抛出异常)。

3. 代码示例:成功与失败的双岔路

这个例子展示了 set_valueset_exception 如何在一个逻辑分支中配合工作:

#include <iostream>
#include <thread>
#include <future>
#include <string>

void dataLoader(std::promise<std::string> prom, bool success) {
    std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时

    if (success) {
        // --- 情况 1:成功 ---
        // 使用 set_value 提交结果
        std::string data = "核心机密数据: 42";
        prom.set_value(data); 
    } else {
        // --- 情况 2:失败 ---
        // 使用 set_exception 提交错误
        try {
            throw std::runtime_error("下载数据超时!");
        } catch (...) {
            prom.set_exception(std::current_exception());
        }
    }
}

int main() {
    // 创建 promise 和 future
    std::promise<std::string> prom;
    std::future<std::string> fut = prom.get_future();

    // 启动线程 (尝试改为 false 看看效果)
    std::thread t(dataLoader, std::move(prom), true);

    std::cout << "主线程:正在等待数据..." << std::endl;

    try {
        // get() 会阻塞,直到 set_value 或 set_exception 被调用
        std::string result = fut.get(); 
        std::cout << "主线程:收到数据 -> " << result << std::endl;
    } catch (const std::exception& e) {
        std::cout << "主线程:捕获异常 -> " << e.what() << std::endl;
    }

    t.join();
    return 0;
}

4. ⚠️ 重要注意事项:只能给一次

std::promise 的承诺是非常严肃的:你只能 set_value 或者 set_exception 一次。

如果你尝试在一个 promise 上调用两次设置(比如先 set_value 了一次,又 set_value 了一次),程序会抛出 std::future_error,错误码为 promise_already_satisfied

prom.set_value(10);
prom.set_value(20); // ❌ 崩溃!抛出 std::future_error

总结: set_value 是多线程通信中“报喜”的通道。配合之前的 set_exception(报忧),它们构成了 C++ std::future 机制完整的结果交付闭环

发表评论