面试二十七、 CAS和Atomic

CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)-CSDN博客

1. ABA问题

在C++中,可以使用std::atomic和版本号来解决ABA问题。C++标准库没有直接提供类似Java的AtomicStampedReference,但可以通过将版本号和指针组合在一起实现类似的效果。

#include <atomic>
#include <iostream>
#include <thread>template <typename T>
class AtomicStampedReference {
public:AtomicStampedReference(T initial_value, int initial_stamp): value_(initial_value), stamp_(initial_stamp) {}bool compare_and_set(T expected_value, T new_value, int expected_stamp, int new_stamp) {auto current_value = value_.load();auto current_stamp = stamp_.load();return (current_value == expected_value && current_stamp == expected_stamp) &&value_.compare_exchange_strong(current_value, new_value) &&stamp_.compare_exchange_strong(current_stamp, new_stamp);}T get_reference() const {return value_.load();}int get_stamp() const {return stamp_.load();}private:std::atomic<T> value_;std::atomic<int> stamp_;
};void aba_example() {AtomicStampedReference<int> atomicStampedRef(100, 0);auto thread1 = [&atomicStampedRef]() {int stamp = atomicStampedRef.get_stamp();int reference = atomicStampedRef.get_reference();std::cout << "Thread 1 initial stamp: " << stamp << "\n";std::cout << "Thread 1 initial value: " << reference << "\n";if (atomicStampedRef.compare_and_set(reference, reference + 1, stamp, stamp + 1)) {std::cout << "Thread 1 new stamp: " << atomicStampedRef.get_stamp() << "\n";std::cout << "Thread 1 new value: " << atomicStampedRef.get_reference() << "\n";}};auto thread2 = [&atomicStampedRef]() {int stamp = atomicStampedRef.get_stamp();int reference = atomicStampedRef.get_reference();atomicStampedRef.compare_and_set(reference, reference + 1, stamp, stamp + 1);atomicStampedRef.compare_and_set(reference + 1, reference, stamp + 1, stamp + 2);std::cout << "Thread 2 stamp after ABA: " << atomicStampedRef.get_stamp() << "\n";std::cout << "Thread 2 value after ABA: " << atomicStampedRef.get_reference() << "\n";};std::thread t1(thread1);std::thread t2(thread2);t1.join();t2.join();
}int main() {aba_example();return 0;
}

2. 自旋时间长开销大

循环时间长开销大

  • 描述:当多个线程竞争同一个CAS操作时,如果一直失败,线程会不断自旋重试,造成CPU资源的浪费。尤其在高并发情况下,频繁的CAS重试会导致较高的CPU开销。
  • 解决办法:可以使用自适应自旋锁或其他锁机制来减轻自旋的开销。

        自旋锁在高竞争情况下会导致大量CPU资源浪费。可以使用自适应自旋锁或结合其他锁机制来减轻这种开销。以下是一个简单的自适应自旋锁实现示例。

#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>class AdaptiveSpinLock {
public:AdaptiveSpinLock() : flag(ATOMIC_FLAG_INIT) {}void lock() {int spin_count = 0;while (flag.test_and_set(std::memory_order_acquire)) {++spin_count;if (spin_count > max_spin_count) {std::this_thread::yield(); // 出让CPUspin_count = 0;}}}void unlock() {flag.clear(std::memory_order_release);}private:static const int max_spin_count = 1000; // 自适应阈值std::atomic_flag flag;
};void spinlock_example() {AdaptiveSpinLock lock;int counter = 0;auto increment = [&lock, &counter]() {for (int i = 0; i < 1000; ++i) {lock.lock();++counter;lock.unlock();}};std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter value: " << counter << "\n";
}int main() {spinlock_example();return 0;
}

3. 多变量原子操作

CAS只能保证单个变量的原子操作,要保证多个变量的原子操作,可以使用锁机制。以下是使用std::mutex来保证多个变量的原子操作的示例。

#include <mutex>
#include <thread>
#include <iostream>class MultiVariable {
public:void update(int a, int b) {std::lock_guard<std::mutex> lock(mtx);var1 = a;var2 = b;}void get(int& a, int& b) {std::lock_guard<std::mutex> lock(mtx);a = var1;b = var2;}private:int var1 = 0;int var2 = 0;std::mutex mtx;
};void multivariable_example() {MultiVariable mv;auto writer = [&mv]() {for (int i = 0; i < 1000; ++i) {mv.update(i, i * 2);}};auto reader = [&mv]() {for (int i = 0; i < 1000; ++i) {int a, b;mv.get(a, b);std::cout << "Read values: " << a << ", " << b << "\n";}};std::thread t1(writer);std::thread t2(reader);t1.join();t2.join();
}int main() {multivariable_example();return 0;
}

4.CAS使用注意事项
(1)CAS需要和volatile配合使用

CAS只能保证变量的原子性,不能保证变量的内存可见性。CAS获取共享变量的值时,需要和volatile配合使用,来保证共享变量的可见性

(2)CAS适用于并发量不高、多核CPU的情况

CPU多核情况下可以同时执行,如果不合适就失败。而并发量过高,会导致自旋重试耗费大量的CPU资源。

5. volatile

  • C++中的volatile:主要用于防止编译器优化,确保每次访问变量时从内存中读取最新的值,但不保证多线程环境下的内存可见性和顺序一致性。
  • 内存可见性:在C++中使用std::atomic和内存序列来确保多线程环境下的内存可见性和顺序一致性。

5.atomic

【超详解】C++原子变量atomic,全面解密!_c++ atomic-CSDN博客

atomic的底层实现 - 王的博客 - 博客园 (cnblogs.com)

CPU多核同步原语 - 知乎 (zhihu.com)

深入解析现代C++中的原子(std::atomic)-51CTO.COM

std::atomic通过硬件提供的原子指令实现无锁的原子操作,确保在多线程环境下的数据一致性和线程安全。通过使用内存顺序,可以进一步控制操作的可见性和顺序,以满足不同的并发编程需求。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/20272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32-C3模组上跑通OTA升级(10)

接前一篇文章&#xff1a;ESP32-C3模组上跑通OTA升级&#xff08;9&#xff09; 八、程序调试过程中遇到的问题及解决 前边各篇文章主要讲解了OTA的基础知识以及示例代码&#xff0c;但这其实是&#xff08;远远&#xff09;不够的&#xff0c;真正要在ESP32-C3芯片上跑通&…

【并发程序设计】13.信号机制

13.信号机制 概念&#xff1a; 信号机制是Unix、类Unix以及其他POSIX兼容的操作系统中的一种进程间通讯方式&#xff0c;它允许进程在发生特定事件时接收通知。 信号机制是操作系统中的一个重要概念&#xff0c;它提供了一种异步的通知机制&#xff0c;用于在进程之间传递消…

【Python】解决Python报错:IndexError: queue index out of range

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

【Unity Shader入门精要 第12章】屏幕后处理效果(二)

1. 卷积 在图像处理中&#xff0c;卷积操作就是使用一个卷积核对一张图像中的每个像素做一系列的操作。 卷积核通常是一个四方形网格结构&#xff0c;如2x2、3x3的方形区域&#xff0c;该区域内每个方格都有一个权重值。 当对图像中的某个像素进行卷积操作时&#xff0c;将卷…

Linux域名解析不了/网络不可达/虚拟机连接不了的问题

记录域名解析不了/网络不可达/虚拟机连接不了的问题问题 目录 文章目录 记录域名解析不了/网络不可达/虚拟机连接不了的问题问题1.首先确定已经连接上路由器(我的就是在这嗝屁了....)1.1 查看路由表1.2查看当前的网络连接状态&#xff0c;包括网关1.3查看网络接口的状态&…

如何解决研发数据传输层面安全可控、可追溯的共性需求?

研发数据在企业内部跨网文件交换&#xff0c;是相对较为普遍而频繁的文件流转需求&#xff0c;基于国家法律法规要求及自身安全管理需要&#xff0c;许多企业进行内部网络隔离。不同企业隔离方案各不相同&#xff0c;比如银行内部将网络隔离为生产网、办公网、DMZ区&#xff0c…

十四天学会Vue——Vue核心下篇(理论+实战)(第三天)

一、Vue核心下篇 1.15 常用的内置指令 1. v-text <!--准备好一个容器 --><div id"root"><!-- 1.v-text中的字符替换掉div整个字符 --><div v-text"name">你好,{{name}}</div><!-- 2.将标签当做字符串解析 --><di…

网络原理-TCP/IP --应用层

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 目录 3.网络原理 -TCP/IP3.1 应用层 3.网络原理 -TCP/IP 3.1 应用层 应用层是程序员打交道最多的一层,与应用程序直接相关 而应用层的协议,实际上就规定了你写的程序,通过网络传输的时候,按…

【LINUX】LINUX基础(目录结构、基本权限、基本命令)

文章目录 LINUX的目录结构LINUX的基本权限LINUX基本命令 LINUX的目录结构 /&#xff1a;表示根目录bin&#xff1a;存放二进制可执行文件(命令ls、cat、mkdir等)boot&#xff1a;存放系统引导文件dev&#xff1a;存放设备文件etc&#xff1a;存放系统配置文件home&#xff1a;…

LeeCode热题100(爬楼梯)

爬楼梯这个题我断断续续看了不下5遍&#xff0c;哪次看都是懵逼的&#xff0c;就会说是满足动态规划&#xff0c;满足斐波那契数列&#xff0c;也不说为什么。 本文一定让你明白怎么分析这个题的规律&#xff08;利用数学的递推思想来分析&#xff09;&#xff0c;看不懂来打我…

1114 全素日

你好哇&#xff0c;新的一天开始啦&#xff01; solution 取数值的不同部分&#xff0c;联想到借助string #include<iostream> #include<string> using namespace std; bool judge(string s){int n atoi(s.c_str());if(n 1 || n 0) return false;for(int i 2…

618大促买什么数码最划算?数码好物清单整理,买到就是赚到!

618年中大促数码产品爱好者们纷纷摩拳擦掌&#xff0c;准备在这个购物狂欢节里抢购心仪已久的数码好物&#xff0c;在繁多的品牌和型号中挑选出最划算的产品&#xff0c;并不是一件容易的事情&#xff0c;为了帮助大家更好地把握这次购物机会&#xff0c;我们精心整理了一份数码…

【qt】多窗口开发

多窗口开发 一.应用场景二.嵌入的窗口1.设计Widget窗口2.创建窗口3.添加窗口4.总代码 三.独立的窗口1.创建窗口2.显示窗口 四.总结 一.应用场景 多窗口,顾名思义,有多个窗口可以供我们进行操作! 截个小图,你应该就知道了 OK,话不多说,直接开干,先来设计我们的主窗口 需要蔬菜…

《异常检测——从经典算法到深度学习》29 EasyTSAD: 用于时间序列异常检测模型的工业级基准

《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …

java mybatis处理大数据量,开启和配置二级缓存,及注意事项,已解决

注意事项&#xff1a; 尽量避免使用下面方式写sql否则会降低服务器性能&#xff1a; mybatis二级缓存开启后&#xff0c;避免使用事务注解&#xff08;加上事务注解后二级缓存数据会导致两次访问不一致问题&#xff09;&#xff1a; 3. 返回的对象实体类&#xff0c;要实现Se…

基恩士激光 速度 曝光等关系

一、基恩士 CtrlN 二、速度设置 计算扫描速度 曝光时间&#xff1a; 1:1 相机点间隔是0.025 &#xff0c;我们要扫描的图像也是1&#xff1a;1的话&#xff0c;速度可以为 采样周期我们设定为3K&#xff0c;假如我们的7000行就够了 速度V0.025&#xff08;线间隔&#xff0…

基于SSM框架的手机商城项目

后端: 订单管理 客户管理&#xff1a; 商品管理 类目管理 前端&#xff1a; 首页&#xff1a;

HTML 转义字符(escape characters)及其对应的符号(symbols)

以下是常见的 HTML 转义字符及其对应的符号&#xff0c;这些可以用于在 HTML 或 JSX 中避免解析错误和特殊字符的冲突&#xff1a; 空格 ( ): 或 引号: 单引号&#xff08;&#xff09;&#xff1a;&apos;、&lsquo;、、&rsquo;双引号&#xff08;"&#x…

字符串 | 字符串匹配之 KMP 算法以及 C++ 代码实现

目录 1 为什么使用 KMP&#xff1f;2 什么是 next 数组&#xff1f;2.1 什么是字符串的前后缀&#xff1f;2.2 如何计算 next 数组&#xff1f; 3 KMP 部分的算法4 完整代码 &#x1f608;前言&#xff1a;这篇文章比较长&#xff0c;但我感觉自己是讲明白了的 1 为什么…

让低代码平台插上AI的翅膀 - 记开源驰骋AI平台升级

让低代码系统插上AI的翅膀——驰骋低代码开发平台引领新时代 在当今日新月异的科技世界中&#xff0c;人工智能&#xff08;AI&#xff09;已经成为各个行业不可或缺的一部分。从制造业的自动化生产到金融行业的智能风控&#xff0c;再到医疗领域的精准诊断&#xff0c;AI技术…