C++11中promise future如何使用

发布时间:2021-07-12 09:32:42 作者:Leah
来源:亿速云 阅读:279
# C++11中promise future如何使用

## 一、引言

在现代多线程编程中,线程间的数据传递和同步是一个核心问题。C++11标准库引入的`<future>`头文件提供了一组强大的工具,其中`promise`和`future`是实现线程间通信的重要机制。本文将深入探讨这对组件的使用方法和原理。

## 二、基本概念

### 2.1 Promise-Future模型

Promise-Future模式是一种典型的异步编程模型,包含两个关键组件:

- **Promise(承诺)**:数据的生产者,负责设置共享状态的值
- **Future(未来)**:数据的消费者,用于获取共享状态的值

### 2.2 与其他机制对比

| 机制          | 通信方向 | 线程安全 | 数据传递方式 |
|---------------|---------|---------|-------------|
| promise/future | 单向    | 是      | 值传递       |
| condition_variable | 双向 | 需配合锁 | 通知机制     |
| atomic         | 双向    | 是      | 直接访问     |

## 三、核心组件详解

### 3.1 std::promise

```cpp
template< class R > class promise;

主要成员函数: - set_value():设置结果值 - set_exception():设置异常 - get_future():获取关联的future对象

3.2 std::future

template< class R > class future;

关键方法: - get():获取结果(会阻塞直到结果就绪) - valid():检查future是否有效 - wait():等待结果就绪 - wait_for()/wait_until():带超时的等待

四、基本使用模式

4.1 简单值传递示例

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

void producer(std::promise<int> prom) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    prom.set_value(42);  // 设置结果值
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();
    
    std::thread t(producer, std::move(prom));
    
    std::cout << "Waiting for value...\n";
    std::cout << "Value: " << fut.get() << "\n";
    
    t.join();
    return 0;
}

4.2 异常传递

void task_with_exception(std::promise<void> prom) {
    try {
        throw std::runtime_error("Error occurred!");
    } catch(...) {
        prom.set_exception(std::current_exception());
    }
}

五、高级用法

5.1 std::shared_future

允许多次获取结果的future:

std::promise<int> prom;
std::shared_future<int> shared_fut = prom.get_future().share();

// 多个线程可以同时访问shared_fut

5.2 配合std::async使用

auto future = std::async(std::launch::async, []{
    return std::string("Hello from async");
});

std::cout << future.get() << std::endl;

5.3 超时处理

std::future<int> fut = /* ... */;
if(fut.wait_for(std::chrono::milliseconds(100)) == 
   std::future_status::ready) {
    // 结果已就绪
} else {
    // 超时处理
}

六、实现原理分析

6.1 共享状态

promise和future通过共享状态(shared state)进行通信,该状态包含: - 结果值或异常 - 就绪标志 - 可能存在的等待线程

6.2 内存模型

共享状态的创建和销毁遵循特定规则: - 由promise创建 - 最后一个引用它的future或promise销毁时释放

七、性能考量

7.1 开销比较

操作 典型耗时
promise创建 ~100ns
future.get()无阻塞 ~50ns
future.get()有阻塞 取决于等待时间

7.2 最佳实践

  1. 避免频繁创建promise/future对
  2. 对热路径考虑无锁方案
  3. 合理使用shared_future减少复制

八、典型应用场景

8.1 异步任务结果获取

std::future<Result> start_async_task() {
    std::promise<Result> prom;
    auto fut = prom.get_future();
    
    std::thread([p = std::move(prom)]() mutable {
        p.set_value(compute_result());
    }).detach();
    
    return fut;
}

8.2 多线程协作

void parallel_processing() {
    std::promise<void> ready_promise;
    std::shared_future<void> ready_future = ready_promise.get_future().share();
    
    auto worker = [ready_future](int id) {
        ready_future.wait();  // 等待开始信号
        // 执行工作...
    };
    
    std::vector<std::thread> workers;
    for(int i = 0; i < 4; ++i) {
        workers.emplace_back(worker, i);
    }
    
    // 准备工作...
    ready_promise.set_value();  // 启动所有worker
    
    for(auto& t : workers) t.join();
}

九、常见问题与解决方案

9.1 错误使用模式

问题1:多次调用set_value

std::promise<int> p;
p.set_value(1);
p.set_value(2);  // 抛出std::future_error

解决:确保每个promise只设置一次值

问题2:忽略future返回值

std::async(std::launch::async, heavy_task);  // 临时future被销毁会阻塞

解决:保存future对象或使用std::future的析构行为

9.2 死锁场景

当多个线程互相等待对方的promise时可能导致死锁。解决方法: 1. 统一设置/获取顺序 2. 使用超时机制 3. 考虑使用std::shared_future

十、与其他特性的结合

10.1 与lambda表达式配合

auto make_ready_future(int value) {
    std::promise<int> p;
    auto f = p.get_future();
    p.set_value(value);
    return f;
}

10.2 在模板编程中的应用

template<typename F, typename... Args>
auto async_retry(F&& f, Args&&... args) 
    -> std::future<decltype(f(args...))>
{
    std::promise<decltype(f(args...))> p;
    auto fut = p.get_future();
    
    std::thread([&]{
        try {
            p.set_value(f(args...));
        } catch(...) {
            p.set_exception(std::current_exception());
        }
    }).detach();
    
    return fut;
}

十一、总结

Promise-Future机制为C++多线程编程提供了强大而灵活的工具,其特点包括: 1. 类型安全的线程间通信 2. 异常安全的错误传递 3. 灵活的结果获取方式

在实际应用中,开发者应当根据具体场景选择合适的同步机制,对于需要返回值传递的异步操作,promise/future通常是首选方案。

附录:完整示例代码

#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <numeric>

// 并行累加示例
double parallel_accumulate(std::vector<double>::iterator begin,
                         std::vector<double>::iterator end) {
    auto len = end - begin;
    if(len < 1000) {
        return std::accumulate(begin, end, 0.0);
    }
    
    auto mid = begin + len/2;
    auto handle = std::async(std::launch::async,
                             parallel_accumulate, mid, end);
    double sum = parallel_accumulate(begin, mid);
    return sum + handle.get();
}

int main() {
    std::vector<double> values(10000, 1.0);
    
    std::future<double> fut = std::async(std::launch::async,
                                        parallel_accumulate,
                                        values.begin(), values.end());
    
    std::cout << "The sum is " << fut.get() << '\n';
    return 0;
}

参考文献

  1. ISO/IEC 14882:2011(E) - C++11标准文档
  2. 《C++并发编程实战》- Anthony Williams
  3. https://en.cppreference.com/w/cpp/thread

”`

推荐阅读:
  1. scala的Promise和Future的理解
  2. C++11的future和promise、parkged_task的用法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++ promise future

上一篇:怎么用LeetCode实现求两数之和

下一篇:Python中的内置数据结构有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》