当前位置: 首页 > news >正文

C++之std::atomic解决多线程7个问题(二百四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:理解C++之std::atomic原子操作解决多线程竟态问题用法。

2.std::atomic可以解决的C++多线程问题

在C++中,std::atomic提供了一种线程安全的访问原子类型的机制,可以解决以下七个多线程之间的问题:

  1. 竞态条件(Race Condition):多个线程同时访问和修改同一个变量时可能导致数据错误。
  2. 内存可见性(Memory Visibility):不同线程对共享变量的修改可能不可见,导致读取到过期的值。
  3. 乱序执行(Out-of-Order Execution):处理器可能以不同的顺序执行指令,导致结果的不确定性。
  4. 死锁(Deadlock):多个线程相互等待对方释放资源,导致程序无法继续执行。
  5. 活锁(Live Lock):多个线程相互响应对方的动作,而无法继续向前推进。
  6. 数据竞争(Data Race):多个线程同时访问和修改共享数据,没有同步机制可能导致不确定的行为。
  7. 优先级反转(Priority Inversion):高优先级任务被低优先级任务持续占用共享资源,导致高优先级任务无法及时执行。

3.应用实例

  1. 竞态条件(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可以避免竞态条件,保证递增操作的原子性。

  1. 内存可见性(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的原子操作来感知到修改,保证内存的可见性。

  1. 乱序执行(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来指定无序存储。

  1. 死锁(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不能直接解决死锁问题,但可以用来作为线程间的通信机制。

  1. 活锁(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;
}

两个线程互相等待对方设置标志位,但由于不断地执行操作和忙等待,两个线程无法继续前进,造成活锁。

  1. 数据竞争(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可以避免数据竞争,保证计数器的正确递增。

  1. 优先级反转(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个问题(二百四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…...

tailwindcss 如何在 uniapp 中使用

直接使用https://tailwindcss.com/docs/guides/vite这篇官方教程的写法是跑不通的&#xff0c;摸索以后整理了一下&#xff0c;最关键的是第6步 npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p在 tailwind.config.js 中写入 export default {conten…...

oracle-使用PLSQL工具自行修改用户密码

1、使用PLSQL工具&#xff0c;输入用户名和原密码登录&#xff0c;如下图 2、登录后&#xff0c;在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码&#xff0c;修改完成后单击”确认”&#xff0c;后退出PLSQL 4、重新打开PLSQL&#xff0c;使用新密码登…...

自动驾驶技术:现状与未来

自动驾驶技术&#xff1a;现状与未来 文章目录 引言自动驾驶技术的现状自动驾驶技术的挑战自动驾驶技术的未来结论结论 2023星火培训【专项营】Apollo开发者社区布道师倾力打造&#xff0c;包含PnC、新感知等的全新专项课程上线了。理论与实践相结合&#xff0c;全新的PnC培训不…...

C++ 类构造函数 析构函数

类的构造函数 类的构造函数是类的一种特殊的成员函数&#xff0c;它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的&#xff0c;并且不会返回任何类型&#xff0c;也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地…...

C++标准模板(STL)- 输入/输出操纵符-(std::get_time,std::put_time)

操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符&#xff08;例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; &#xff09;实现为接受到流的引用为其唯一参数的函数。 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&#xff09;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杂货店】类和对象&#xff08;上&#xff09; 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类对象模型7.1 类对象的存储规则7.2 例题7.3结构体内存对齐规则 八、this指针8.2 t…...

web:[极客大挑战 2019]PHP

题目 点进页面显示如下 根据页面提示&#xff0c;这个网站有备份文件&#xff0c;备份文件一般是bak文件格式&#xff0c;用dirsearch扫描 访问之后下载了一个文件 里面都是一些代码 在index.php中发现了一个类的文件&#xff0c;一个get传参&#xff0c;然后将传进的值进行反序…...

Firefox 开发团队对 Vue 3 进行优化效果显著

Mozilla 官方博客近日发表文章《Faster Vue.js Execution in Firefox》&#xff0c;介绍了 Firefox 开发团队对 Vue 3 进行的优化。 文章写道&#xff0c;在使用 Speedometer 3 对 Firefox 进行基准测试时&#xff0c;他们发现 Vue.js test 的测试结果从 Vue 2 升级到 Vue 3 后…...

【Verilog 教程】6.5 Verilog避免Latch

关键词&#xff1a;触发器&#xff0c;锁存器 Latch 的含义 锁存器&#xff08;Latch&#xff09;&#xff0c;是电平触发的存储单元&#xff0c;数据存储的动作取决于输入时钟&#xff08;或者使能&#xff09;信号的电平值。仅当锁存器处于使能状态时&#xff0c;输出才会随着…...

怒刷LeetCode的第21天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;哈希表 方法二&#xff1a;计数器数组 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;分治法 方法二&#xff1a;快速幂 迭代 方法三&#xff1a;快速幂 递归 第三题 题目来源 题目内容 …...

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 应用中起着关键作用&#xff0c;而 FastAPI、Sanic、Tornado 都声称具有卓越的性能。本文将通过性能压测对这些框架与Go的Gin框架进行全面对比&#xff0c;揭示它们之间的差异。 原文&#xff1a;Python异步框架大战&#xff1a;FastAPI、Sa…...

Docker笔记1

一、Docker介绍 Docker是一个开源的应用容器引擎&#xff0c;基于Go语言并遵从Apache2.0协议开源 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。 容器是完全使用沙箱机制&a…...

TensorFlow-Federated简介与安装

1、简介 TensorFlow Federated&#xff08;TFF&#xff09;是一个用于机器学习和其他分布式数据计算的开源框架。TFF 的开发旨在促进联邦学习 &#xff08;FL&#xff09;的开放研究和实验。联邦学习是一种机器学习方法&#xff0c;其中一个共享的全局模型在许多参与的客户之间…...

【强化学习】基础概念

1. Agent (智能体) 智能体是进行决策和学习的实体&#xff0c;它能感知环境的状态&#xff0c;并基于策略采取动作以影响环境。智能体的目标是通过与环境的交互获得最大化的累积奖励。 2. Environment (环境) 环境是智能体所处的外部系统&#xff0c;它与智能体交互。环境的…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...