C++ 11新特性之并发
概述
随着计算机硬件的发展,多核处理器已经成为主流,对程序并发执行能力的需求日益增长。C++ 11标准引入了一套全面且强大的并发编程支持库,为开发者提供了一个安全、高效地利用多核CPU资源进行并行计算的新框架,极大地简化了多线程开发。
std::thread
在C++ 11中,std::thread是用于创建和管理线程的核心组件。使用线程的一些要点如下。
1、创建线程。
通过调用std::thread构造函数,传入要在线程中执行的函数(或可调用对象)以及任何必要的参数来创建线程。
2、线程函数。
可以是一个全局函数、类成员函数(此时需要传递指向该类实例的指针或引用),或者是一个满足Callable要求的类型。
3、线程执行。
一旦创建了std::thread对象,线程就会尝试启动执行,但具体何时开始执行由操作系统调度决定。
4、线程同步。
若多个线程共享数据,通常需要使用互斥锁(std::mutex)、条件变量(std::condition_variable)或其他同步机制来避免竞态条件和数据不一致问题。
5、线程生命周期管理。
join()方法会阻塞当前线程,直到被调用join()的线程完成其任务。detach()方法将线程从std::thread对象中分离,使其成为一个守护线程,当主线程退出而未调用join()时,这个分离的线程仍然可以继续运行。但是,如果分离的线程最后仍在运行且没有其他引用,则可能会导致资源泄漏。
std::thread的具体使用,可参考下面的示例代码。
#include <iostream>
#include <thread>
using namespace std;void ThreadFunc()
{cout << "Sub thread" << endl;
}int main() {thread myThread(ThreadFunc);cout << "Main thread init" << endl;myThread.join();cout << "Main thread exit" << endl;return 0;
}
std::mutex
std::mutex是用于实现线程间同步的基础工具,它确保同一时间内只有一个线程能够访问被保护的资源或执行一段代码。为了简化锁的管理并防止死锁,通常建议使用std::lock_guard或std::unique_lock这样的RAII(Resource Acquisition Is Initialization)机制来自动管理锁的生命周期。同时,在复杂的情况下,还可以结合条件变量等工具来实现更为灵活的线程同步逻辑。
在<mutex>头文件中定义了std::mutex类型,它代表一个可重入互斥量。当多个线程试图同时获取已锁定的互斥量时,除了已经持有该互斥量的线程外,其他线程会被阻塞直到互斥量被解锁。std::mutex的主要成员函数如下。
1、构造函数:默认构造一个未锁定的互斥量。
std::mutex mtx;
2、lock():将互斥量锁定,如果互斥量已经被另一个线程锁定,则调用此方法的线程将被阻塞,直至互斥量变为可用。
mtx.lock();
3、unlock():解锁互斥量,允许等待的线程(如果有)获得所有权并继续执行。
mtx.unlock();
4、try_lock():尝试锁定互斥量,但不会阻塞。如果成功获取锁则返回true,否则(即互斥量已被锁定)立即返回false。
if (mtx.try_lock())
{// 已经获取到锁
}
else
{// 未能获取到锁
}
5、RAII包装器类。为了确保即使在异常情况下也能正确释放互斥锁,C++ 11提供了几个基于RAII(Resource Acquisition Is Initialization)原则的包装器类,比如:std::lock_guard和std::unique_lock。
std::lock_guard:当lock_guard对象创建时自动锁定互斥量,并在其析构时自动解锁互斥量,从而避免忘记解锁导致的死锁问题。
std::lock_guard<std::mutex> lock(mtx);
// 这里是受保护的代码区域
// lock析构时,自动解锁
std::unique_lock:提供了比lock_guard更多的灵活性,比如:手动锁定、解锁以及尝试锁定等。
std::condition_variable
condition_variable是C++标准库中的一个同步原语,它是多线程编程中的一种关键工具,主要用于线程间的通信和同步。它与互斥量(mutex)配合使用,可以实现线程的等待和通知机制。具体来说,std::condition_variable类提供了以下的功能。
1、等待。
当某个条件不满足时,线程可以调用wait()函数释放互斥锁并进入等待状态,直到其他线程对同一个条件变量调用notify_one()或notify_all()函数唤醒它。
2、唤醒。
notify_one():唤醒一个正在等待此条件变量的线程(如果有多个线程在等待,则唤醒其中一个)。
notify_all():唤醒所有正在等待此条件变量的线程。
通常,condition_variable的典型使用场景包括:生产者/消费者模式、 barrier同步等,通过它可以有效地控制线程在满足特定条件时才继续执行,从而避免无效的循环检查或者竞争条件等问题。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;static mutex s_mutex;
static condition_variable s_condition;
static bool s_bReady = false;void PrintID(int nID)
{unique_lock<mutex> lock(s_mutex);while (!s_bReady){// 当ready为false时,线程会一直等待s_condition.wait(lock);}// 当其他线程修改ready为true,并调用cv.notify_all()后,这里会被唤醒cout << "Thread " << nID << " is running." << endl;
}void Process()
{unique_lock<mutex> lock(s_mutex);s_bReady = true;// 唤醒所有等待的线程s_condition.notify_all();
}int main()
{thread pThreads[10];for (int i = 0; i < 10; ++i){pThreads[i] = thread(PrintID, i + 1);}// 创建一个线程来修改ready并唤醒其他线程thread threadOther(ref(Process));for (auto& t : pThreads){t.join();}threadOther.join();return 0;
}
在上面的示例代码中,我们创建了10个线程,它们都在等待一个条件:s_bReady变为true。当Process线程将s_bReady设为true并调用s_condition.notify_all()后,所有等待的线程都会被唤醒,并打印自己的ID。
std::atomic
std::atomic是C++ 11引入的标准库中的一个模板类,它提供了一种能够在多线程环境中进行原子操作的类型安全方式。原子操作意味着:即使在没有互斥量或其他同步机制的情况下,该操作也能够从多个线程中以不可分割的方式执行,即不会出现半个操作的现象,确保了数据一致性。
使用std::atomic可以有效地处理简单的同步需求,比如:无锁计数器、标志位等,并且相比传统的互斥锁而言,其开销通常更小,性能更高。
#include <atomic>
#include <thread>
#include <cassert>
using namespace std;static atomic<int> s_nCounter(0);void Increment()
{++s_nCounter;
}int main()
{thread t1(Increment);thread t2(Increment);t1.join();t2.join();// 这个断言总是成立,因为s_nCounter的递增是原子的assert(s_nCounter == 2);return 0;
}
std::atomic支持多种类型的对象,包括但不限于:基本内置类型、指针以及用户自定义类型(如果满足特定条件)。它提供了load、store、exchange、compare_exchange_strong/weak等一系列原子操作方法,用于读写和更新其内部封装的数据成员。
std::future和std::async
std::future 和 std::async是C++ 11标准引入的异步编程工具,它们位于<future>头文件中,用于简化并发任务的管理和结果的获取。
std::future是一个模板类,它代表了一个可以在未来某个时间点获取的结果。当你启动一个异步计算时,该计算的结果可以通过std::future对象来访问。std::future 提供了以下功能。
获取结果:调用std::future::get()会阻塞当前线程,直到异步计算完成并返回结果。
检查是否已准备好:可以检查future是否已经包含有效结果或异常。
取消异步操作:虽然不能直接取消异步操作,但可以关联一个可取消的共享状态,然后取消那个状态。
获取异常:如果异步计算过程中抛出了异常,则可以在future上捕获到这个异常。
std::async是一个函数模板,它用来异步执行一个函数,并返回一个表示其结果的std::future对象。
#include <iostream>
#include <future>
#include <chrono>
using namespace std;int LongTimeCompute(int nNumber)
{// 模拟耗时操作this_thread::sleep_for(chrono::seconds(5));return nNumber * nNumber;
}int main()
{// 使用async启动异步任务auto future_result = async(launch::async, LongTimeCompute, 10);cout << "Main thread running..." << endl;// 当需要结果时,调用get()int nResult = future_result.get();cout << "Result of async computing: " << nResult << endl;return 0;
}
在上面的示例代码中,我们定义了一个模拟耗时计算的函数LongTimeCompute。然后,在main函数中,我们通过std::async创建了一个异步任务,并指定其策略为std::launch::async,确保在新的线程上运行该函数。
主线程在等待异步任务完成的同时可以继续执行其他任务,当主线程需要得到异步任务的结果时,它调用了 future_result.get(),这将阻塞直到异步计算完成并将结果返回给主线程。最后,主线程输出了异步计算得到的结果。
总结
C++ 11提供的并发特性不仅简化了多线程编程的复杂性,而且增强了程序的安全性和可靠性。通过合理利用这些工具和技术,我们能够更好地设计和实现适应现代多核架构的应用程序,从而提升软件的整体性能表现。在实践中,还需注意避免死锁、竞态条件等并发问题,并结合实际情况选择适当的并发策略。正确理解和熟练运用C++ 11的并发库,是构建高效、稳定且可扩展应用程序的关键。
相关文章:
C++ 11新特性之并发
概述 随着计算机硬件的发展,多核处理器已经成为主流,对程序并发执行能力的需求日益增长。C 11标准引入了一套全面且强大的并发编程支持库,为开发者提供了一个安全、高效地利用多核CPU资源进行并行计算的新框架,极大地简化了多线程…...
jvm问题自查思路
本文聊一下最近处理了一些jvm的问题上,将这个排查和学习过程分享一下,看了很多资料,最终都会落地到几个工具的使用,本文主要是从文档学习、工具学习和第三方技术验证来打开认知和实践,希望有用。 一、文档 不仅知道了…...
任意IOS16系统iPad/Iphone开启台前调度
方法来自GitHub: GitHub - khanhduytran0/TrollPad: Troll SpringBoard into thinking its running on iPadOS 注意操作前iPad/iPhone上需要安装巨魔手机助手和Filza,关于这两个软件的安装自行百度方法。 备注一个巨魔手机助手的下载地址 Release TrollStar 1.2…...
LeetCode、452. 用最少数量的箭引爆气球【中等,贪心,区间问题】
文章目录 前言LeetCode、452. 用最少数量的箭引爆气球【中等,贪心,区间问题】题目链接与分类思路贪心,连续区间数量问题 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客…...
洛谷C++简单题小练习day10—umi的函数
day10--umi的函数--2.13 习题概述 题目背景 umi 找到了一个神秘的函数 f。 题目描述 这个函数接受两个字符串 s1,s2。这些字符串只能由小写字母组成并且具有相同的长度。这个函数的输出是另一个长度与 s1,s2 相同的字符串 g。 g 的第 i 个字符等于 s1 的第 i 个字符和 s2…...
【Linux学习】线程互斥与同步
目录 二十.线程互斥 20.1 什么是线程互斥? 20.2 为什么需要线程互斥? 20.3 互斥锁mutex 20.4 互斥量的接口 20.4.1 互斥量初始 20.4.2 互斥量销毁 20.4.3 互斥量加锁 20.4.4 互斥量解锁 20.4.5 互斥量的基本原理 20.4.6 带上互斥锁后的抢票程序 20.5 死锁问题 死锁…...
前端开发:(三)CSS入门
1. 介绍CSS 1.1 什么是CSS CSS(Cascading Style Sheets)是一种用于描述文档样式和布局的样式表语言,用于美化和排版HTML和XML等标记语言的内容。 1.2 CSS的作用和优势 CSS的主要作用是控制网页的样式和布局,包括字体、颜色、间…...
一周学会Django5 Python Web开发-Django5创建项目(用PyCharm工具)
锋哥原创的Python Web开发 Django5视频教程: 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计11条视频,包括:2024版 Django5 Python we…...
寒假学习记录13:JS对象
目录 对象转数组 对象双值转数组 Object.entries() (转为二维数组)(属性的值和键) 对象右值转数组 Object.values() (属性的值) 对象左值转数组 Object.keys() (属性的键) 对象左值转…...
学生成绩管理系统|基于Springboot的学生成绩管理系统设计与实现(源码+数据库+文档)
学生成绩管理系统目录 目录 基于Springboot的学生成绩管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能模块 2、学生功能模块 3、教师功能模块 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源…...
C#向数组指定索引位置插入新的元素值:自定义插入方法 vs List<T>.Add(T) 方法
目录 一、使用的方法 1.自定义插入方法 2.使用List.Add(T) 方法 二、实例 1.示例1:List.Add(T) 方法 2.示例:自定义插入方法 一、使用的方法 1.自定义插入方法 首先需要定义一个一维数组,然后修改数组的长度(这里使用Length属性获取…...
【大数据Hive】hive 表设计常用优化策略
目录 一、前言 二、hive 普通表查询原理 2.1 操作演示说明 2.1.1 创建一张表,并加载数据 2.1.2 统计3月24号的登录人数 2.1.3 查询原理过程总结 2.2 普通表结构带来的问题 三、hive分区表设计 3.1 区表结构 - 分区设计思想 3.2 操作演示 3.2.1 创建分区表…...
jvm垃圾收集器之七种武器
目录 1.回收算法 1.1 标记-清除算法(Mark-Sweep) 1.2 复制算法(Copying) 1.3 标记-整理算法(Mark-Compact) 2.HotSpot虚拟机的垃圾收集器 2.1 新生代的收集器 Serial 收集器(复制算法) ParNew 收集器 (复制算法) Parallel Scavenge 收集器 (复制…...
STM32面试相关问题
STM32面试相关问题: STM32的内核型号,主频,传感器和单片机总线类型,IIC,SPI,RS485UART数据帧项目中一些参数的设置 STM32 系统移植 ARM编译 常用的驱动编写方式 自己写过哪些方面驱动 其实如果问32的问题,…...
风行智能电视N39S、N40 强制刷机升级方法,附刷机升级数据MstarUpgrade.bin
升级步骤: 1、下载刷机数据,如是压缩包,需要先解压,然后将刷机bin格式的文件重命名为MstarUpgrade.bin 2、将此文件放到U盘根目录 (U盘格式FAT32,单分区,建议4G的优盘刷机成功率高)…...
【C语言】简易英语词典
文章目录 一、定义英语单词信息的结构体二、主函数功能逻辑三、查单词函数四、背单词函数五、补充 一、定义英语单词信息的结构体 添加必要的头文件、宏定义和声明,之后定义英语单词信息结构体。 /* 头文件和宏定义 */ #include <stdio.h> #include <std…...
【算法题】104. 二叉树的最大深度
题目 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:3 示例 2: 输入:root [1,nul…...
Docker配置Portainer容器管理界面
目录 一、Portainer 简介 优点: 缺点: 二、环境配置 1. 拉取镜像 2. 创建启动容器 三、操作测试 1. 进入容器 2. 拉取镜像并部署 3. 访问测试 一、Portainer 简介 Portainer 是一个开源的轻量级容器管理界面,用于管理 Docker 容器…...
Linux network namespace 访问外网以及多命名空间通信(经典容器组网 veth pair + bridge 模式认知)
写在前面 整理K8s网络相关笔记博文内容涉及 Linux network namespace 访问外网方案 Demo实际上也就是 经典容器组网 veth pair bridge 模式理解不足小伙伴帮忙指正 不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已…...
网络渗透测试:Wireshark抓取qq图片
Wireshark Wireshark Downloadhttps://www.wireshark.org/download.html 简介 WireShark是非常流行的网络封包分析工具,可以截取各种网络数据包,并显示数据包详细信息。常用于开发测试过程中各种问题定位。本文主要内容包括: 1、Wireshar…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
