C++中的异步编程:std::future与std::promise的结合

C++中的异步编程:std::future与std::promise的结合

欢迎来到今天的讲座!今天我们要聊一聊C++中一个非常有趣的话题——异步编程。如果你曾经在写程序时遇到过“等待”这个问题,那么你一定会对今天的主题感兴趣。想象一下,你的程序就像一个餐馆的服务员,如果他一直在厨房门口等着厨师做完菜再服务下一位客人,那效率肯定低得可怜。而我们今天要讲的std::futurestd::promise,就是帮助我们的服务员更高效地工作的好帮手!

异步编程是什么?

在传统的同步编程中,程序按照代码的顺序一步一步执行,每一步都必须等到前一步完成才能继续。而在异步编程中,程序可以同时处理多个任务,不需要一直等待某个任务完成。这就像是让服务员可以先去招呼其他客人,等厨师做好菜后再回来取餐。

std::future 和 std::promise 是什么?

  • std::future 是一个容器,用来存储未来的结果。你可以把它想象成一个快递包裹,你现在下单了,但货物还在路上。
  • std::promise 是一个生产者,用来设置这个未来的结果。它就像是快递公司,负责把货物送到你下单的地方。

两者的关系可以用一句话概括:std::promise 设置结果,std::future 获取结果。

让我们来看一个简单的例子

假设我们需要计算两个数的和,但是这个计算可能需要一些时间,所以我们想让它在后台进行,而不阻塞主线程。

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

int main() {
    // 创建一个 promise 对象
    std::promise<int> sumPromise;

    // 获取 future 对象
    std::future<int> sumFuture = sumPromise.get_future();

    // 启动一个线程来计算两个数的和
    std::thread t([&sumPromise]() {
        int a = 10, b = 20;
        std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
        sumPromise.set_value(a + b); // 设置结果
    });

    std::cout << "Waiting for the result..." << std::endl;

    // 等待结果并获取
    int result = sumFuture.get(); // 阻塞直到结果可用

    std::cout << "The result is: " << result << std::endl;

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

在这个例子中,我们创建了一个std::promise对象,并通过它获得了std::future对象。然后我们在一个独立的线程中计算两个数的和,并使用set_value方法将结果传递给std::future。主线程会一直等待,直到std::future有结果为止。

std::future 和 std::promise 的状态

状态 描述
ready 结果已经准备好,可以通过 get() 方法获取
not ready 结果还没有准备好,调用 get() 会阻塞,直到结果准备好
invalid std::future 对象已经被移动或销毁,无法再获取结果

std::future 的常见用法

除了上面提到的get()方法,std::future还有一些其他有用的方法:

  • wait(): 主动等待结果,不会返回任何值。
  • wait_for(): 等待一段时间后返回,如果在这段时间内结果没有准备好,则返回std::future_status::timeout
  • wait_until(): 等待到指定的时间点,如果到那时结果还没有准备好,则返回std::future_status::timeout

std::promise 的常见用法

  • set_value(): 设置结果的值。
  • set_exception(): 设置异常,用于处理可能出现的错误。

实战演练:多线程数据处理

让我们再来看一个稍微复杂一点的例子,假设我们需要从多个线程中收集数据,并将它们汇总在一起。

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

// 模拟耗时的数据处理函数
int processData(int data) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return data * 2;
}

int main() {
    std::vector<std::future<int>> futures;
    std::vector<std::promise<int>> promises;

    // 创建多个 promise 和 future 对象
    for (int i = 0; i < 5; ++i) {
        std::promise<int> promise;
        promises.push_back(std::move(promise));
        futures.push_back(promises.back().get_future());
    }

    // 启动多个线程来处理数据
    for (size_t i = 0; i < promises.size(); ++i) {
        std::thread t([i, &promises]() {
            int result = processData(i);
            promises[i].set_value(result); // 设置结果
        });
        t.detach(); // 分离线程
    }

    // 收集所有结果
    int total = 0;
    for (auto& fut : futures) {
        total += fut.get(); // 获取每个线程的结果
    }

    std::cout << "Total result: " << total << std::endl;

    return 0;
}

在这个例子中,我们创建了多个std::promisestd::future对象,并启动了多个线程来处理数据。每个线程处理完数据后,都会通过std::promise将结果传递给对应的std::future。最后,我们在主线程中收集所有结果并计算总和。

总结

今天我们一起探讨了C++中std::futurestd::promise的结合使用。通过这两个工具,我们可以轻松实现异步编程,提高程序的效率。记住,std::promise是用来设置结果的,而std::future是用来获取结果的。希望今天的讲座对你有所帮助,下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注