C++中的异步编程:std::future
与std::promise
的结合
大家好!今天我们要聊一聊C++中非常有趣的一对搭档——std::future
和std::promise
。它们就像是异步编程世界里的“情侣”,总是形影不离。如果你正在学习C++的并发编程,那么这对组合你一定得了解。别担心,我会用轻松幽默的方式带你走进它们的世界。
什么是异步编程?
在正式介绍主角之前,我们先简单聊聊异步编程是什么。想象一下,你在厨房里做饭,同时还在接电话。你不需要等水烧开才能接听电话,对吧?这就是异步编程的核心思想:让程序能够同时处理多个任务,而不需要阻塞主线程。
C++提供了多种工具来实现异步编程,其中std::future
和std::promise
就是一对重要的搭档。接下来,让我们逐一认识它们。
std::future
:未来的承诺
std::future
是一个类模板,它代表了一个“未来”的值。你可以把它想象成一个快递包裹——你现在下单了,但快递员还没送到。等到包裹到了,你就可以打开它查看内容。
特点:
- 它是只读的,只能获取结果。
- 它可以从
std::promise
、std::async
或std::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::future
从std::async
中获取了一个计算结果。我们在主线程中调用了fut.get()
,这会阻塞直到计算完成。
std::promise
:许下承诺
std::promise
是std::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::future
与std::promise
的结合
现在我们已经分别认识了std::future
和std::promise
,接下来让我们看看它们是如何携手合作的。
工作流程:
- 创建一个
std::promise
对象。 - 使用
std::promise::get_future()
获取一个对应的std::future
对象。 - 在一个线程中使用
std::promise
设置结果。 - 在另一个线程中使用
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::future
和std::promise
的作用及其协作方式。它们是C++异步编程的重要工具,帮助我们编写更加高效和灵活的程序。
最后引用一段来自《C++ Concurrency in Action》的话:“std::future
和std::promise
提供了一种简单的方式来解耦生产者和消费者之间的关系。”希望今天的讲解对你有所帮助!
如果你还有任何疑问,欢迎随时提问!