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

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

大家好!今天我们要聊一聊C++中非常有趣的一对搭档——std::futurestd::promise。它们就像是异步编程世界里的“情侣”,总是形影不离。如果你正在学习C++的并发编程,那么这对组合你一定得了解。别担心,我会用轻松幽默的方式带你走进它们的世界。


什么是异步编程?

在正式介绍主角之前,我们先简单聊聊异步编程是什么。想象一下,你在厨房里做饭,同时还在接电话。你不需要等水烧开才能接听电话,对吧?这就是异步编程的核心思想:让程序能够同时处理多个任务,而不需要阻塞主线程。

C++提供了多种工具来实现异步编程,其中std::futurestd::promise就是一对重要的搭档。接下来,让我们逐一认识它们。


std::future:未来的承诺

std::future是一个类模板,它代表了一个“未来”的值。你可以把它想象成一个快递包裹——你现在下单了,但快递员还没送到。等到包裹到了,你就可以打开它查看内容。

特点:

  • 它是只读的,只能获取结果。
  • 它可以从std::promisestd::asyncstd::packaged_task中获取值。

代码示例:

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

int main() {
    std::future<int> fut = std::async(std::launch::async, []() {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        return 42;
    });

    std::cout << "Waiting for the result...n";
    int result = fut.get(); // 阻塞直到结果可用
    std::cout << "Result: " << result << "n";

    return 0;
}

在这个例子中,std::futurestd::async中获取了一个计算结果。我们在主线程中调用了fut.get(),这会阻塞直到计算完成。


std::promise:许下承诺

std::promisestd::future的另一半,它是用来设置未来值的对象。你可以把它看作是快递公司——它负责准备包裹,并通知快递员去送。

特点:

  • 它可以设置值(set_value)或异常(set_exception)。
  • 每个std::promise对象都关联着一个std::future对象。

代码示例:

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

void worker(std::promise<int>& prom) {
    try {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        if (true) { // 假设计算成功
            prom.set_value(100); // 设置结果
        } else {
            throw std::runtime_error("Something went wrong!");
        }
    } catch (...) {
        prom.set_exception(std::current_exception()); // 设置异常
    }
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t(worker, std::ref(prom));

    try {
        std::cout << "Waiting for the result...n";
        int result = fut.get(); // 阻塞直到结果可用
        std::cout << "Result: " << result << "n";
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << "n";
    }

    t.join();
    return 0;
}

在这个例子中,std::promise负责计算并设置结果,而std::future则负责获取结果。如果计算过程中抛出了异常,std::promise也会将异常传递给std::future


std::futurestd::promise的结合

现在我们已经分别认识了std::futurestd::promise,接下来让我们看看它们是如何携手合作的。

工作流程:

  1. 创建一个std::promise对象。
  2. 使用std::promise::get_future()获取一个对应的std::future对象。
  3. 在一个线程中使用std::promise设置结果。
  4. 在另一个线程中使用std::future获取结果。

表格总结:

功能 std::future std::promise
数据流向 获取结果 设置结果
是否阻塞 调用get()时可能阻塞 不阻塞
异常处理 可以捕获异常 可以设置异常

实战演练:模拟银行转账

为了让大家更好地理解这对搭档的实际应用,我们来写一个简单的银行转账程序。

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

void transferMoney(std::promise<int> prom, int amount) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    prom.set_value(amount); // 模拟转账成功
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t(transferMoney, std::move(prom), 500);

    try {
        std::cout << "Transfer in progress...n";
        int transferredAmount = fut.get(); // 等待转账完成
        std::cout << "Transferred amount: " << transferredAmount << "n";
    } catch (const std::exception& e) {
        std::cerr << "Transfer failed: " << e.what() << "n";
    }

    t.join();
    return 0;
}

在这个例子中,std::promise负责模拟转账操作,而std::future负责等待转账结果。


总结

通过今天的讲座,我们深入了解了std::futurestd::promise的作用及其协作方式。它们是C++异步编程的重要工具,帮助我们编写更加高效和灵活的程序。

最后引用一段来自《C++ Concurrency in Action》的话:“std::futurestd::promise提供了一种简单的方式来解耦生产者和消费者之间的关系。”希望今天的讲解对你有所帮助!

如果你还有任何疑问,欢迎随时提问!

发表回复

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