讲座主题:C++中的异步编程神器——std::promise 和 std::future
开场白
各位程序员朋友们,大家好!今天咱们来聊聊C++中的一对“黄金搭档”——std::promise
和std::future
。如果你觉得多线程编程像一场复杂的舞蹈,那么这两个家伙就是你的舞伴,帮你把节奏踩得稳稳的。
在现代C++中,异步编程已经成为了一种非常流行的编程模式。它允许我们在不阻塞主线程的情况下执行耗时任务,从而提升程序的性能和响应速度。而std::promise
和std::future
正是实现这一目标的重要工具。别担心,今天的讲座我会用轻松幽默的方式,带你一步步掌握它们的用法。
第一节:初识std::future
首先,我们来认识一下std::future
。你可以把它想象成一个“未来”的容器,它会保存某个操作的结果。当你发起一个异步任务时,std::future
就像是一个快递单号,你可以用它随时查询任务的状态或者获取最终的结果。
代码示例1:简单的std::future使用
#include <iostream>
#include <future>
#include <thread>
int main() {
// 创建一个std::future对象
std::future<int> futureResult = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return 42;
});
std::cout << "Waiting for the result..." << std::endl;
// 获取结果(阻塞直到结果可用)
int result = futureResult.get();
std::cout << "The result is: " << result << std::endl;
return 0;
}
讲解:
std::async
是C++标准库提供的一个函数,用于启动异步任务。std::future
在这里充当了结果的“快递单号”,我们可以用.get()
方法获取最终的结果。- 注意:
.get()
是一个阻塞操作,如果结果还没准备好,它会一直等待。
第二节:std::promise登场
接下来,我们再看看std::promise
。如果说std::future
是一个“未来”的容器,那么std::promise
就是一个“承诺”。它负责将结果传递给对应的std::future
。换句话说,std::promise
是生产者,std::future
是消费者。
代码示例2:std::promise的基本用法
#include <iostream>
#include <future>
#include <thread>
void worker(std::promise<int> &&pr) {
try {
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作
pr.set_value(42); // 设置结果
} catch (...) {
pr.set_exception(std::current_exception()); // 如果有异常,可以设置异常
}
}
int main() {
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future(); // 获取关联的future
std::thread t(worker, std::move(promiseObj)); // 将promise传递给worker线程
std::cout << "Waiting for the worker to finish..." << std::endl;
try {
int result = futureObj.get(); // 获取结果
std::cout << "Worker returned: " << result << std::endl;
} catch (const std::exception &e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
t.join(); // 等待线程结束
return 0;
}
讲解:
std::promise
通过.set_value()
方法将结果传递给关联的std::future
。- 如果任务中抛出了异常,可以用
.set_exception()
方法将异常传递给std::future
。 std::future
可以通过.get()
方法捕获异常并处理。
第三节:std::promise与std::future的协作
现在我们已经分别了解了std::promise
和std::future
,接下来让我们看看它们是如何协同工作的。
表格对比:std::promise vs std::future
特性 | std::promise | std::future |
---|---|---|
角色 | 生产者 | 消费者 |
主要用途 | 设置异步任务的结果 | 获取异步任务的结果 |
是否可以共享结果 | 不支持共享 | 支持通过std::shared_future 共享 |
常见方法 | .set_value() , .set_exception() |
.get() , .wait() , .valid() |
代码示例3:std::promise与std::future的协作
#include <iostream>
#include <future>
#include <thread>
void producer(std::promise<int> &&pr) {
std::this_thread::sleep_for(std::chrono::seconds(2));
pr.set_value(100); // 设置结果
}
void consumer(std::future<int> fu) {
std::cout << "Consumer is waiting..." << std::endl;
int result = fu.get(); // 获取结果
std::cout << "Consumer received: " << result << std::endl;
}
int main() {
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
std::thread producerThread(producer, std::move(promiseObj));
std::thread consumerThread(consumer, std::move(futureObj));
producerThread.join();
consumerThread.join();
return 0;
}
讲解:
- 在这个例子中,
std::promise
负责生成结果,而std::future
负责消费结果。 - 通过分离生产和消费逻辑,我们可以更灵活地设计异步任务。
第四节:常见问题与注意事项
-
std::future的阻塞问题
.get()
方法会阻塞当前线程,直到结果可用。如果不想阻塞,可以使用.wait_for()
或.wait_until()
来检查结果是否就绪。 -
std::promise的移动语义
std::promise
对象不能被复制,只能通过移动语义传递。这是因为它的内部状态需要独占访问。 -
异常处理
如果异步任务中抛出了异常,可以通过.set_exception()
将异常传递给std::future
,并在.get()
时捕获。
结语
今天的讲座到这里就结束了!希望你对std::promise
和std::future
有了更深的理解。它们就像一对默契的搭档,帮助你在C++中轻松实现异步编程。记住,异步编程虽然强大,但也需要谨慎设计,避免出现死锁或数据竞争等问题。
最后,引用《C++ Concurrency in Action》这本书中的一句话:“并发编程不仅仅是让程序跑得更快,更是为了让程序更加健壮和可维护。”希望大家在学习异步编程的过程中,既能享受技术的乐趣,也能写出优雅的代码!
谢谢大家,下次再见!