使用std::promise 和 std::future处理异步操作和并发编程

43 阅读2分钟

在 C++ 中,std::promisestd::future 是用于处理异步操作和并发编程的重要组件。它们通常一起使用,以便在一个线程中设置值,并在另一个线程中获取这些值。这种机制使得线程之间的通信变得简单且安全。

1. std::promise

std::promise 是一个模板类,可以用来为某个值提供一个“承诺”,这种值通常是计算结果。当你在一个线程中完成某项工作时,可以利用 std::promise 来设置这个结果。其他线程可以通过与之关联的 std::future 来访问这个结果。

基本语法

#include <future>

2. std::future

std::future 用于获取未来的值,它与 std::promise 直接相关联。通过 std::future,你可以等待异步操作的结果,同时保证线程安全。

基本语法

#include <future>

3. 使用示例

以下是一个简单的示例,展示了如何使用 std::promisestd::future 在不同线程之间传递值。

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

void calculateFactorial(int n, std::promise<int> prom) {
    int result = 1;
    for (int i = 1; i <= n; ++i) {
        result *= i;
    }
    // 将计算结果传递给 Promise
    prom.set_value(result);
}

int main() {
    // 创建一个 promise 和对应的 future
    std::promise<int> prom;
    std::future<int> fut = prom.get_future(); // 从 promise 获取 future

    // 启动一个线程来计算阶乘
    std::thread t(calculateFactorial, 5, std::move(prom));

    // 等待结果并输出
    std::cout << "Calculating factorial...\n";
    int result = fut.get(); // 阻塞直到结果准备好
    std::cout << "Factorial: " << result << std::endl;

    // 等待线程结束
    t.join();
    return 0;
}

4. 代码解析

  1. 创建 Promise 和 Future

    • std::promise<int> 创建一个 promise 对象,用于传递 int 类型的值。
    • prom.get_future() 返回与 prom 关联的 future 对象。
  2. 启动线程

    • 使用 std::thread 来运行 calculateFactorial 函数。在这个函数中会执行阶乘的计算,并将结果存储到 Promise 中。
  3. 阻塞等待结果

    • 在主线程中调用 fut.get(),这将阻塞当前线程,直到 Promise 被满足(即设置了值)。
  4. 输出结果

    • 一旦 result 可用,程序将输出计算的阶乘结果。
  5. 清理线程

    • 使用 t.join() 确保主线程等待子线程完成执行。

5. 异常处理

如果在 set_value 之前发生异常,你可以使用 set_exception 来处理错误:

void safeCalculateFactorial(int n, std::promise<int> prom) {
    try {
        if (n < 0) throw std::runtime_error("Negative input");
        int result = 1;
        for (int i = 1; i <= n; ++i) {
            result *= i;
        }
        prom.set_value(result);
    } catch (...) {
        prom.set_exception(std::current_exception());
    }
}

6. 总结

  • std::promisestd::future 提供了 C++ 中简洁的方式来进行线程间通信。
  • 它们允许在一个线程中生成值,并在另一个线程中安全地获取这些值。
  • 使用 Promise 和 Future 时,注意处理异常情况,以确保程序的健壮性。