C++11线程库futures与promises

发布时间: 2024-12-10 02:55:33 阅读量: 1 订阅数: 12
DOCX

C++线程库介绍

![C++11线程库futures与promises](https://inprogrammer.com/wp-admin/admin-ajax.php?action=rank_math_overlay_thumb&id=5261&type=play&hash=ac518a8d00bb7c7902e8d2fc2ce600c2) # 1. C++11线程库概述与基础 ## 简介 C++11 引入了一套全新的线程库,它提供了一种高层次的并发编程机制。这个库的引入,极大简化了多线程程序的设计和实现,使得开发者可以更容易地利用现代多核处理器的能力。 ## 历史背景 在 C++11 之前,多线程编程往往依赖于平台特定的扩展或者第三方库。标准库的缺乏导致代码可移植性差,难以维护。为了解决这些问题,C++11 纳入了包括线程、互斥锁、条件变量、futures 和 promises 在内的多线程相关组件。 ## 核心组件概览 C++11 线程库主要包含以下几个核心组件: - `thread`:用于表示和控制线程。 - `mutex`、`lock`、`condition_variable`:用于线程同步和互斥。 - `async`、`future`、`promise`:用于在不同线程之间传递数据和异常。 ## C++11 线程库的优势 C++11 线程库的设计哲学着重于易于理解和使用。它为多线程的创建、执行和管理提供了一套直观的抽象,支持基于任务的并发模式,并且能够与现代 C++ 编程风格(如 lambda 表达式)无缝集成。 C++11 线程库的推出,使得编写可移植、高效的多线程代码成为可能,是学习现代 C++ 并发编程不可或缺的一部分。接下来的章节中,我们将深入探讨 futures 和 promises,以及如何利用它们解决实际的并发编程问题。 # 2. 理解futures的使用和原理 ## 2.1 futures简介 ### 2.1.1 futures的概念和作用 在C++11线程库中,`futures`是并发编程中一个非常重要的概念,它提供了一种机制,允许异步任务的结果在将来某个时间点被检索。简单来说,`future`是一个对象,它异步地从另一个线程获取数据,而获取数据的操作可能还未完成或甚至还未开始。在C++中,`std::future`是实现这一功能的模板类。 `futures`的主要作用包括: 1. 提供异步操作的返回值访问。 2. 允许多个线程等待同一个异步操作的结果。 3. 隔离同步和异步代码部分,提高代码的可读性和维护性。 使用`future`可以将线程间的依赖降到最低,因为创建`future`对象的线程不需要等待其代表的异步操作完成,可以继续执行其他任务。而当需要结果时,只需在`future`对象上调用等待操作,即可暂停当前线程,直到异步操作完成并可安全访问结果。 ### 2.1.2 创建和获取futures 创建一个`future`对象通常涉及启动一个异步操作,并将其与`future`对象相关联。在C++11中,可以使用`std::async`启动异步操作,也可以通过`std::packaged_task`或`std::promise`手动包装异步任务。 - 使用`std::async`启动异步任务: ```cpp #include <future> #include <iostream> int main() { // 启动一个异步任务计算结果 std::future<int> future_result = std::async(std::launch::async, []() { return 42; }); // 获取异步任务的结果 int result = future_result.get(); // 返回42 std::cout << "The answer is " << result << std::endl; return 0; } ``` - 使用`std::packaged_task`: ```cpp #include <future> #include <iostream> int main() { // 准备一个任务,比如计算某个函数的值 std::packaged_task<int()> task([]() { return 42; }); // 获取future对象 std::future<int> future_result = task.get_future(); // 执行任务 task(); // 获取任务结果 int result = future_result.get(); // 返回42 std::cout << "The answer is " << result << std::endl; return 0; } ``` 在上述代码中,我们演示了如何使用`std::async`和`std::packaged_task`创建`future`对象并获取异步操作的结果。需要注意的是,在调用`future.get()`之前,如果对应的任务尚未完成,当前线程将会阻塞,直到获取到结果。另外,如果一个`future`对象在它所关联的异步操作完成前被销毁,则该操作会被中断,调用`get()`时会抛出异常。 ## 2.2 futures的类型和特性 ### 2.2.1 std::future与std::shared_future的区别 `std::future`和`std::shared_future`都是从异步操作中检索值的工具,但它们有细微的差别。 `std::future`: - 通常用于单次异步结果的检索。 - 不能被复制,但可以被移动。 - 当`std::future`对象被销毁时,它所关联的异步操作会被取消,除非已经获取了它的值。 `std::shared_future`: - 可以关联同一异步操作的多个结果。 - 允许多个线程多次获取值,且这些调用彼此之间不会互相影响。 - 可以被复制,适用于多个线程需要等待同一个异步操作的不同结果的场景。 例如,如果需要在多个线程中重复获取某个异步操作的结果,应当使用`std::shared_future`。 ```cpp #include <future> #include <iostream> int main() { std::promise<int> prom; std::shared_future<int> sfut(prom.get_future()); std::vector<std::thread> threads; for(int i = 0; i < 5; ++i) { threads.emplace_back([sfut]() { int value = sfut.get(); // 在不同的线程中多次获取值 std::cout << "Value retrieved: " << value << std::endl; }); } prom.set_value(42); // 设置异步操作的结果 // 等待所有线程完成 for(auto& t : threads) { t.join(); } return 0; } ``` ### 2.2.2 futures中的异常处理 当异步操作产生异常时,异常信息会被存储在`future`对象中。使用`get()`方法时,如果异步操作失败,会抛出异常,并将异常信息传递给调用者。因此,正确地处理`get()`抛出的异常非常重要,尤其是在多线程环境中。 ```cpp #include <future> #include <iostream> #include <stdexcept> int main() { // 异步任务中产生异常 std::promise<int> prom; auto future_result = prom.get_future(); std::thread t([&prom]() { try { // 异步任务执行中抛出异常 throw std::runtime_error("Error occurred"); } catch (...) { // 将异常封装进promise中 prom.set_exception(std::current_exception()); } }); // 获取异步任务的结果 try { int result = future_result.get(); std::cout << "Result: " << result << std::endl; } catch (const std::exception& e) { // 异步操作中的异常被捕获 std::cout << "Caught exception: " << e.what() << std::endl; } t.join(); return 0; } ``` 在这个例子中,我们创建了一个异步任务,并在任务中故意抛出了一个异常。这个异常被`set_exception`方法捕获,并在后续使用`get()`方法时被抛出。正确地处理这种情况对于保证程序的健壮性至关重要。 ## 2.3 futures的实践应用 ### 2.3.1 异步计算示例 利用`std::async`和`std::future`可以很轻易地实现异步计算。下面是一个异步计算的例子: ```cpp #include <future> #include <iostream> #include <chrono> int compute(int n) { std::this_thread::sleep_for(std::chrono::seconds(1)); return n * n; } int main() { // 启动异步任务计算平方值 std::future<int> result = std::async(std::launch::async, compute, 99); // 在等待结果的时候,执行其他任务 std::cout << "Doing something else meanwhile..." << std::endl; // 获取异步任务的结果 int square = result.get(); std::cout << "The result is " << square << std::endl; return 0; } ``` 在这个示例中,我们利用`std::async`启动了一个异步计算任务,并立即返回了一个`std::future`对象,表示这个异步任务的结果。主线程在等待结果的同时,执行了其他任务,而不是简单地空等。这种模式在实际应用中可以大幅提升程序的响应性和吞吐量。 ### 2.3.2 使用futures进行并发控制 `futures`可以用于控制异步任务的执行顺序。通过确保在继续执行之前某个异步任务必须完成,我们可以实现并发控制。 ```cpp #include <future> #include <iostream> #include <thread> void task1(std::promise<int>& prom) { std::this_thread::sleep_for(std::chrono::seconds(2)); prom.set_value(1); // 任务1完成 } void task2(std::future<int>& fut) { int value = fut.get(); // 等待任务1完成 std::cout << "Task 2 started after Task 1 with value: " << value << std::endl; } int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t1(task1, std::ref(prom)); std::thread t2(task2, std::ref(fut)); t1.join(); t2.join(); return 0; } ``` 在这个例子中,`task1`和`task2`是两个异步任务,其中`task2`需要等待`task1`完成后才能开始执行。这通过`promise`和`future`对象实现。`task1`完成之后通过`set_value`方法设置值,然后`task2`通过`get`方法检索该值以继续执行。这种模式可用于更复杂的并发任务,确保它们按照特定顺序执行。 在下一章中,我们将继续深入理解`promises`的原理,以及它们如何与`futures`紧密协作以实现复杂的并发控制。 # 3. promises的深入剖析 在并发编程中,promises是一个核心概念,允许一个线程提供一个值给另一个线程,而这个值可能在未来某个时刻才会被计算出来。在C++11中,std::promise及其对应的std::future提供了一种机制来实现线程间的数据同步和异步结果的传递。本章节我们将深入剖析promises的内部工作原理以及如何将它们与futures结合起来使用,展示其在并发编程中的强大功能。 ## 3.1 promises基本原理 ### 3.1.1 promises的概念 在C++11中,`std::promise`是一个模板类,它可以存储一个值或者一个异常。存储的值或异常可以在将来某个时刻通过`std::future`来检索。`std::promise`通常用于异步计算中,其中一个线程执行一些工作并设置结果,而其他线程通过`std::future`等待并获取这个结果。 ```cpp std::promise<int> prom; // 创建一个int类型的promise对象 std::future<int> fut = prom.get_future(); // 获取与promise关联的future对象 // ... 在另一个线程中执行一些计算 ... prom.set_value(42); // 设置计算结果,调用线程将阻塞直到结果被获取 std::cout << fut.ge ```
corwn 最低0.47元/天 解锁专栏
买1年送1年
点击查看下一篇
profit 百万级 高质量VIP文章无限畅学
profit 千万级 优质资源任意下载
profit C知道 免费提问 ( 生成式Al产品 )

相关推荐

SW_孙维

开发技术专家
知名科技公司工程师,开发技术领域拥有丰富的工作经验和专业知识。曾负责设计和开发多个复杂的软件系统,涉及到大规模数据处理、分布式系统和高性能计算等方面。
专栏简介
《C++多线程编程的技巧与方法》专栏深入探讨了C++多线程编程的方方面面。从入门指南到高级主题,该专栏涵盖了以下内容: * C++11线程库的深入理解 * 线程池的设计与实现 * 条件变量的使用技巧 * 多线程调试的艺术 * 并发算法 * 多线程内存模型 * 死锁防范 * 性能调优 * 设计模式 * 线程安全单例模式实现 * 多线程与分布式系统 本专栏旨在为C++开发人员提供全面的指南,帮助他们掌握多线程编程的复杂性,并构建高性能、可扩展和可靠的多线程应用程序。
最低0.47元/天 解锁专栏
买1年送1年
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
C知道 免费提问 ( 生成式Al产品 )

最新推荐

【地震波成像技术】:揭秘FK分析在波场映射中的惊人作用

![【地震波成像技术】:揭秘FK分析在波场映射中的惊人作用](http://www.stdaily.com/index/kejixinwen/2020-02/25/887584/images/f78f4a17b3a14eec9e8cdd96ea6bf365.jpg) 参考资源链接:[Lupei Zhu教授的FK工具包:水平分层模型格林函数计算与地震图合成教程](https://wenku.csdn.net/doc/6412b70abe7fbd1778d48e0d?spm=1055.2635.3001.10343) # 1. 地震波成像技术概述 ## 1.1 地震波成像技术简介 地震波成像技

CAM350故障排除速成:开短路问题的快速诊断与解决法

![CAM350故障排除速成:开短路问题的快速诊断与解决法](https://gdm-catalog-fmapi-prod.imgix.net/ProductScreenshot/ce296f5b-01eb-4dbf-9159-6252815e0b56.png?auto=format&q=50) 参考资源链接:[CAM350检查开短路](https://wenku.csdn.net/doc/6469cf105928463033e20285?spm=1055.2635.3001.10343) # 1. CAM350软件与PCB开短路问题概述 在现代电子制造领域,电路板(PCB)是几乎所有电子

【专家视角】SONY IMX 178高速成像性能评测:性能优化的秘密武器

![【专家视角】SONY IMX 178高速成像性能评测:性能优化的秘密武器](https://i0.wp.com/www.techarp.com/wp-content/uploads/2019/08/Sony-IMX586-feature-slide.jpg?resize=960%2C539&ssl=1) 参考资源链接:[索尼IMX178:高性能CMOS图像传感器技术解析](https://wenku.csdn.net/doc/2e2hfcxefh?spm=1055.2635.3001.10343) # 1. SONY IMX 178高速成像传感器概述 SONY IMX 178是一款具有

空间分析与数据处理技巧:Geomatica 2020高级功能深度探索

![空间分析与数据处理技巧:Geomatica 2020高级功能深度探索](https://colegiodeingenieria.com/wp-content/uploads/2022/04/ingenieria-geomatica-1-1.jpg) 参考资源链接:[PCI Geomatica2020中文用户手册:从入门到精通](https://wenku.csdn.net/doc/32ehwsi2un?spm=1055.2635.3001.10343) # 1. Geomatica 2020概览与基础应用 随着地理信息系统(GIS)技术的快速发展,Geomatica 2020作为一款强

【C#新手必看】:ListBox控件字体颜色个性化设置完全手册

![ListBox控件](https://urbanfonts-files.s3.amazonaws.com/samples/3283/5afb739e87d49882c597ca5dd0f6ff87.jpg) 参考资源链接:[C# ListBox 中指定行字体颜色修改教程](https://wenku.csdn.net/doc/5a83kp9z0v?spm=1055.2635.3001.10343) # 1. ListBox控件简介与应用基础 ## 概述 ListBox控件是许多软件开发平台中不可或缺的元素,尤其在需要展示可选择列表的场景中。它为用户界面提供了基础的交互方式,支持垂直或水

SP Flash Tool 高级使用指南:定制化刷机流程与技巧

![SP Flash Tool 高级使用指南:定制化刷机流程与技巧](https://www.thecustomdroid.com/wp-content/uploads/2020/07/Flash-Stock-Firmware-on-MediaTek-Android-Device-using-SP-Flash-Tool.jpg) 参考资源链接:[SPFlashTool刷机教程:步骤详解与注意事项](https://wenku.csdn.net/doc/6412b4d8be7fbd1778d41068?spm=1055.2635.3001.10343) # 1. SP Flash Tool概述

【HFSS 3D Layout性能优化】:快速调整布局的4种方法,提升效率

![【HFSS 3D Layout性能优化】:快速调整布局的4种方法,提升效率](https://public.fangzhenxiu.com/fixComment/commentContent/imgs/1679540347294_m1lkpv.jpg?imageView2/0) 参考资源链接:[HFSS 3D Layout用户手册:全面指南](https://wenku.csdn.net/doc/6412b6edbe7fbd1778d48793?spm=1055.2635.3001.10343) # 1. HFSS 3D Layout简介与性能挑战 ## 1.1 HFSS 3D Lay

【HDMI音频技术深度解析】:不同版本音频传输能力的全面评估

![HDMI 各版本差异分析](https://www.cuidevices.com/image/getimage/94045?typecode=m) 参考资源链接:[HDMI各版本详解:1.3a至2.0技术飞跃与差异对比](https://wenku.csdn.net/doc/6460bc8e5928463033af8f6e?spm=1055.2635.3001.10343) # 1. HDMI音频技术概述 HDMI(High-Definition Multimedia Interface)不仅已成为高清视频传输的标准接口,而且在音频传输方面也扮演着至关重要的角色。它通过单一的电缆连接,

汇川MD310变频器:维护与保养的5大黄金法则

![MD310变频器](http://www.szyxwkj.com/UploadFiles/FCK/2022-09/6379997433431305774286067.png) 参考资源链接:[汇川MD310系列变频器用户手册:功能特性与使用指南](https://wenku.csdn.net/doc/8bnnqnnceg?spm=1055.2635.3001.10343) # 1. 汇川MD310变频器概述 ## 1.1 MD310变频器的简介 汇川MD310变频器是一款在工业自动化领域广泛应用的电力控制设备。它是通过改变供电频率与电压来控制电动机转速的装置,从而达到提高电能使用效率和

Fanuc PLC编程黄金法则:打造高效的自动化流程

![Fanuc PLC编程黄金法则:打造高效的自动化流程](https://img-blog.csdnimg.cn/direct/0ff8f696bf07476394046ea6ab574b4f.jpeg) 参考资源链接:[FANUC机器人自动运行设置详解:RSR与PNS启动](https://wenku.csdn.net/doc/12rv1nsph5?spm=1055.2635.3001.10343) # 1. Fanuc PLC编程概述 在自动化控制系统领域,Fanuc PLC(可编程逻辑控制器)已经成为标准设备。本章旨在为读者提供一个对Fanuc PLC编程的总体认识。我们将从PLC