C++之std::atomic解决多线程7个问题(二百四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
1.前言
本篇目的:理解C++之std::atomic原子操作解决多线程竟态问题用法。
2.std::atomic
可以解决的C++多线程问题
在C++中,std::atomic提供了一种线程安全的访问原子类型的机制,可以解决以下七个多线程之间的问题:
- 竞态条件(Race Condition):多个线程同时访问和修改同一个变量时可能导致数据错误。
- 内存可见性(Memory Visibility):不同线程对共享变量的修改可能不可见,导致读取到过期的值。
- 乱序执行(Out-of-Order Execution):处理器可能以不同的顺序执行指令,导致结果的不确定性。
- 死锁(Deadlock):多个线程相互等待对方释放资源,导致程序无法继续执行。
- 活锁(Live Lock):多个线程相互响应对方的动作,而无法继续向前推进。
- 数据竞争(Data Race):多个线程同时访问和修改共享数据,没有同步机制可能导致不确定的行为。
- 优先级反转(Priority Inversion):高优先级任务被低优先级任务持续占用共享资源,导致高优先级任务无法及时执行。
3.应用实例
- 竞态条件(Race Condition):
v1.0 未使用atomic原子操作
#include <atomic>
#include <thread>
#include <cstdio>//std::atomic<int> counter(0); // 原子变量
int counter = 0; // 普通变量void increment() {for (int i = 0; i < 1000; i++) {counter++; // 原子操作:递增printf("counter = %d\n",counter);//打印出来的数据是乱序的}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}
v2.0 使用atomic原子操作
#include <atomic>
#include <thread>std::atomic<int> counter(0); // 原子变量void increment() {for (int i = 0; i < 1000; i++) {counter++; // 原子操作:递增printf("counter = %d\n",counter.load());//按顺序打印0 - 2000. }
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}
多个线程同时对counter进行递增操作,使用std::atomic可以避免竞态条件,保证递增操作的原子性。
- 内存可见性(Memory Visibility):
#include <atomic>
#include <thread>
#include <iostream>std::atomic<bool> flag(false); // 原子标志void run() {while (!flag.load()) {// do something}printf("flag = %d\n",flag.load());
}int main() {std::thread t(run);// 假设这里执行一些耗时的计算std::this_thread::sleep_for(std::chrono::seconds(1));flag.store(true); // 原子操作:标志位置为truet.join();return 0;
}
flag作为一个标志位,在一个线程中修改为true,其他线程可以通过读取flag的原子操作来感知到修改,保证内存的可见性。
- 乱序执行(Out-of-Order Execution):
#include <atomic>
#include <thread>
#include <iostream>std::atomic<int> value(0); // 原子变量void write() {value.store(42, std::memory_order_relaxed); // 原子操作:无序存储
}void read() {while (value.load(std::memory_order_relaxed) == 0) {// do something}std::cout << "Value: " << value.load(std::memory_order_relaxed) << std::endl;
}int main() {std::thread t1(write);std::thread t2(read);t1.join();t2.join();return 0;
}
通过使用适当的内存顺序(memory_order)来进行原子操作,可以避免乱序执行带来的问题,例如使用std::memory_order_relaxed来指定无序存储。
- 死锁(Deadlock):
#include <atomic>
#include <mutex>
#include <thread>std::atomic<bool> flag1(false);
std::atomic<bool> flag2(false);std::mutex mutex1;
std::mutex mutex2;void process1() {mutex1.lock(); // 获取锁1// 假设这里执行一些操作flag1.store(true); // 标记为已处理mutex2.lock(); // 获取锁2// 执行需要锁2的操作mutex2.unlock();mutex1.unlock();
}void process2() {mutex2.lock(); // 获取锁2// 假设这里执行一些操作flag2.store(true); // 标记为已处理mutex1.lock(); // 获取锁1// 执行需要锁1的操作mutex1.unlock();mutex2.unlock();
}int main() {std::thread t1(process1);std::thread t2(process2);t1.join();t2.join();return 0;
}
多个线程对两个互斥量(mutex)进行获取操作,可能导致死锁,std::atomic不能直接解决死锁问题,但可以用来作为线程间的通信机制。
- 活锁(Live Lock):
#include <atomic>
#include <thread>
#include <iostream>std::atomic<bool> flag1(false);
std::atomic<bool> flag2(false);void process1() {while (!flag2) {// 假设这里执行一些操作// 暂停一段时间,避免忙等待std::this_thread::sleep_for(std::chrono::milliseconds(100));flag1.store(true);// 假设这里还有其他判断逻辑}
}void process2() {while (!flag1.load()) {// 假设这里执行一些操作// 暂停一段时间,避免忙等待std::this_thread::sleep_for(std::chrono::milliseconds(100));flag2.store(true);// 假设这里还有其他判断逻辑}
}int main() {std::thread t1(process1);std::thread t2(process2);t1.join();t2.join();std::cout << "Live lock detected!" << std::endl;return 0;
}
两个线程互相等待对方设置标志位,但由于不断地执行操作和忙等待,两个线程无法继续前进,造成活锁。
- 数据竞争(Data Race):
#include <atomic>
#include <thread>
#include <iostream>std::atomic<int> counter(0); // 原子计数器void increment() {for (int i = 0; i < 1000; i++) {int temp = counter.load(); // 读取计数器的当前值counter.store(temp + 1); // 原子操作:递增}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Counter: " << counter.load() << std::endl;return 0;
}
两个线程同时读取和修改计数器的值,使用std::atomic可以避免数据竞争,保证计数器的正确递增。
- 优先级反转(Priority Inversion):
#include <atomic>
#include <thread>
#include <iostream>std::atomic<int> sharedResource(0); // 共享资源void lowPriorityThread() {while (true) {// 低优先级任务需要访问共享资源while (sharedResource.load() == 0) {// do something}std::cout << "Low priority thread accessing shared resource." << std::endl;// 假设这里执行一些低优先级任务的操作// 完成低优先级任务后释放共享资源sharedResource.store(0);}
}void highPriorityThread() {// 高优先级任务需要持有共享资源sharedResource.store(1);std::cout << "High priority thread acquired shared resource." << std::endl;// 假设这里执行一些高优先级任务的操作// 完成高优先级任务后释放共享资源sharedResource.store(0);
}int main() {std::thread t1(lowPriorityThread);std::thread t2(highPriorityThread);t1.join();t2.join();return 0;
}
相关文章:
C++之std::atomic解决多线程7个问题(二百四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
tailwindcss 如何在 uniapp 中使用
直接使用https://tailwindcss.com/docs/guides/vite这篇官方教程的写法是跑不通的,摸索以后整理了一下,最关键的是第6步 npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p在 tailwind.config.js 中写入 export default {conten…...
oracle-使用PLSQL工具自行修改用户密码
1、使用PLSQL工具,输入用户名和原密码登录,如下图 2、登录后,在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码,修改完成后单击”确认”,后退出PLSQL 4、重新打开PLSQL,使用新密码登…...
自动驾驶技术:现状与未来
自动驾驶技术:现状与未来 文章目录 引言自动驾驶技术的现状自动驾驶技术的挑战自动驾驶技术的未来结论结论 2023星火培训【专项营】Apollo开发者社区布道师倾力打造,包含PnC、新感知等的全新专项课程上线了。理论与实践相结合,全新的PnC培训不…...
C++ 类构造函数 析构函数
类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地…...
C++标准模板(STL)- 输入/输出操纵符-(std::get_time,std::put_time)
操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符(例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; )实现为接受到流的引用为其唯一参数的函数。 basic_ostream::…...
蓝桥等考Python组别九级004
第一部分:选择题 1、Python L9 (15分) 运行下面程序,可以输出几行“*”?( ) for i in range(3): for j in range(4): print(*, end = ) print() 2345正确答案:B 2、Python L9...
gitee 远程仓库操作基础(二)
(1)clone远端仓库,本地建立分支推送 (基于远程仓库版本库 本地建立分支开发新功能) git clone gitgitee.com:xxxxx/alsa_test.git git remote add origin gitgitee.com:xxxxx/alsa_test.git进入clone过后路径代码,查看本地分支,发现该项目远程仓库有很多分支 基于…...
Scala第四章节
Scala第四章节 scala总目录 章节目标 掌握分支结构的格式和用法掌握for循环和while循环的格式和用法掌握控制跳转语句的用法掌握循环案例理解do.while循环的格式和用法 1. 流程控制结构 1.1 概述 在实际开发中, 我们要编写成千上万行代码, 代码的顺序不同, 执行结果肯定也…...
【C++入门指南】类和对象(上)
【C杂货店】类和对象(上) 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类对象模型7.1 类对象的存储规则7.2 例题7.3结构体内存对齐规则 八、this指针8.2 t…...
web:[极客大挑战 2019]PHP
题目 点进页面显示如下 根据页面提示,这个网站有备份文件,备份文件一般是bak文件格式,用dirsearch扫描 访问之后下载了一个文件 里面都是一些代码 在index.php中发现了一个类的文件,一个get传参,然后将传进的值进行反序…...
Firefox 开发团队对 Vue 3 进行优化效果显著
Mozilla 官方博客近日发表文章《Faster Vue.js Execution in Firefox》,介绍了 Firefox 开发团队对 Vue 3 进行的优化。 文章写道,在使用 Speedometer 3 对 Firefox 进行基准测试时,他们发现 Vue.js test 的测试结果从 Vue 2 升级到 Vue 3 后…...
【Verilog 教程】6.5 Verilog避免Latch
关键词:触发器,锁存器 Latch 的含义 锁存器(Latch),是电平触发的存储单元,数据存储的动作取决于输入时钟(或者使能)信号的电平值。仅当锁存器处于使能状态时,输出才会随着…...
怒刷LeetCode的第21天(Java版)
目录 第一题 题目来源 题目内容 解决方法 方法一:哈希表 方法二:计数器数组 第二题 题目来源 题目内容 解决方法 方法一:分治法 方法二:快速幂 迭代 方法三:快速幂 递归 第三题 题目来源 题目内容 …...
Armv9 Cortex-A720的L2 memory system 和 L2 Cache
9 L2 memory system Cortex-A720核心的L2内存系统通过CPU bridge连接core与DynamIQ Shared Unit-120,其中包括私有的L2缓存。 L2缓存是统一的,每个Cortex-A720核心在一个集群中都有私有的L2缓存。 L2内存系统包括使用虚拟地址(VA)和程序计数器(PC)的数据预取引擎。不同…...
蓝桥等考Python组别九级003
第一部分:选择题 1、Python L9 (15分) 运行下面程序,可以输出几行“*”?( ) for i in range(3): for j in range(4): print(*, end = ) print() 6374正确答案:B 2、Python L9...
Python异步框架大战:FastAPI、Sanic、Tornado VS Go 的 Gin
一、前言 异步编程在构建高性能 Web 应用中起着关键作用,而 FastAPI、Sanic、Tornado 都声称具有卓越的性能。本文将通过性能压测对这些框架与Go的Gin框架进行全面对比,揭示它们之间的差异。 原文:Python异步框架大战:FastAPI、Sa…...
Docker笔记1
一、Docker介绍 Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。 容器是完全使用沙箱机制&a…...
TensorFlow-Federated简介与安装
1、简介 TensorFlow Federated(TFF)是一个用于机器学习和其他分布式数据计算的开源框架。TFF 的开发旨在促进联邦学习 (FL)的开放研究和实验。联邦学习是一种机器学习方法,其中一个共享的全局模型在许多参与的客户之间…...
【强化学习】基础概念
1. Agent (智能体) 智能体是进行决策和学习的实体,它能感知环境的状态,并基于策略采取动作以影响环境。智能体的目标是通过与环境的交互获得最大化的累积奖励。 2. Environment (环境) 环境是智能体所处的外部系统,它与智能体交互。环境的…...
云原生Kubernetes:K8S集群各组件服务重启
目录 一、理论 1.各组件服务重启命令 一、理论 1.各组件服务重启命令 (1)Master节点Node节点共同服务 systemctl restart etcd systemctl daemon-reload systemctl enable flanneld systemctl restart flanneld (2)Master节…...
闲话Python编程-循环
1. for循环 Python的for语句有点特别,只能对序列和字符串进行处理,序列自然包括list、tuple和range对象。 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # 练习for语句def loop_for():names [Tom, Jack, Black]for name in names:print(name)s ab…...
建筑能源管理(3)——建筑能源监管
为了全面落实科学发展观,提高建筑能源管理水平,进一步降低能源和水资源消耗、合理利用资源,以政府办公建筑和大型公共建筑的运行节能管理为突破口,建立了既有政府办公建筑和大型公共建筑运行节能监管体系,旨在提高政府…...
中国逐年干燥度指数数据集
简介: 中国逐年干燥度指数,空间分辨率为1km,时间为1901-2022,为比值,没有单位。该数据集是基于中国1km逐月潜在蒸散发(PET)和降水量(PRE)采用比值法计算式得到ÿ…...
Azure Arc 概要:功能、管理和应用场景详解,AZ900 考点示例
文章目录 本文大纲一、什么是 Azure Arc二、使用 Azure Arc 可以做什么操作三、使用 Azure Arc 可以管理什么资源3.1 如何使用Azure Arc与服务器? 四、Azure Arc 支持的主要场景五、在 AZ900 中的考点示例5.1 示例题 15.2 示例题 2 本文大纲 本文思维导图概述的主要内容&…...
JavaScript Web APIs第一天笔记
复习: splice() 方法用于添加或删除数组中的元素。 **注意:**这种方法会改变原始数组。 删除数组: splice(起始位置, 删除的个数) 比如:1 let arr [red, green, blue] arr.splice(1,1) // 删除green元素 consol…...
十六.镜头知识之工业镜头的质量判断因素
十六.镜头知识之工业镜头的质量判断因素 文章目录 十六.镜头知识之工业镜头的质量判断因素1.分辨率(Resolution)2.明锐度(Acutance)3.景深(DOF):4. 最大相对孔径与光圈系数5.工业镜头各参数间的相互影响关系5.1.焦距大小的影响情况5.2.光圈大小的影响情况5.3.像场中…...
网络协议--概述
1.2 分层 网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能。一个协议族,比如TCP/IP,是一组不同层次上的多个协议的组合。 TCP/IP通常被认为是一个四层协议系统,如图1-1所示。每一层负责不同的功能: 1.链…...
aarch64 平台 musl gcc 工具链手动编译方法
目标 手动编译一个 aarch64 平台的 musl gcc 工具链 musl libc 与 glibc、uclibc 等,都是 标准C 库, musl libc 是基于系统调用之上的 标准C 库,也就是用户态的 标准C 库。 musl libc 轻量、开源、免费,是一些 操作系统的选择,当前 Lite-OS 与 RT-Smart 等均采用自制的 mu…...
计算机图像处理-高斯滤波
高斯滤波 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到…...
腾达建设哪里的/整站优化方案
rsync 学习 参考 http://www.cnblogs.com/itech/archive/2009/08/10/1542945.html 模式1 本地直接拷贝, 这个其实是调用了 cp 命令, 跟 rsync 服务器, 客户端无关。 /usr/myapp/logs 是本地日志目录 rsync /usr/myapp/logs /usr/myapp/logs2 …...
做网站三年3万块钱/常用的关键词挖掘工具
首先谈一下最简单的Bash博弈。Bash博弈是这样的:两个人,n个物品,每个人每次都可以取走1-m个物品,取走最后一个物品的人胜利。问先手在什么条件下必胜。 #include <bits/stdc.h> #define ll long long #define inf 0x3f3f3f…...
做彩票网站代理/淘宝大数据查询平台
如何玩转iPhone手机?最近手机连接投影仪被大家关注,那么苹果手机是如何连接投影仪的呢?新出的iPhone8可以连接吗?跟随小编一起来了解一下详细的步骤教程吧。苹果手机与投影仪连接的方法教程(步骤) 1、第一次…...
北京app网站建设/网站建设seo优化培训
本文档介绍 Mplayer 如何移植到 IMX6Q 开发板 QT5.7 系统上,并有几个简单的测试例程。相关的配套资料在网盘资料“iTOP-i.MX6 开发板资料汇总(不含光盘资料)\08_iTOP-i.MX6 开发板 Linux 系统开发资料\19-QT5.7 系统 Mplayer 移植”下 64.1 …...
网站如何做团购/数据分析
layout拼图安卓版是一款典型的拼图应用,可以让我们把各种照片随心所欲地拼起来,也是轻量级应用的模式打造,整个应用程序非常的轻便,虽然在开发商算不上独一无二的,但绝对是实用标准的拼图应用。功能介绍Instagram 全新…...
做柱状图 饼状图的网站/软文营销的本质
上一篇文章中已经配置缓存服务器,这里说说主DNS服务器的配置:涉及相关知识:资源记录:SOA:资源起始记录,放在配置文件的第一条A记录:域名指向IP地址AAAA记录:域名指向IPV6地址PTR记录…...