Linux C/C++并发编程实战(8)CAS机制的ABA问题

文章目录

    • 无锁队列中的ABA问题
    • ABA问题解决方案

ABA问题:CAS在操作的时候会检查变量的值是否被更改过,如果没有则更新值,但是带来一个问题,最开始的值是A,接着变成B,最后又变成了A。经过检查这个值确实没有修改过,因为最后的值还是A,但是实际上这个值确实已经被修改过了。

听起来似乎没有什么严重的问题,举几个实际的例子看下。

无锁队列中的ABA问题

/* Naive lock-free stack which suffers from ABA problem.*/
class Stack {std::atomic<Obj*> top_ptr;//// Pops the top object and returns a pointer to it.//Obj* Pop() {while (1) {Obj* ret_ptr = top_ptr;if (ret_ptr == nullptr) return nullptr;// For simplicity, suppose that we can ensure that this dereference is safe// (i.e., that no other thread has popped the stack in the meantime).Obj* next_ptr = ret_ptr->next;// If the top node is still ret, then assume no one has changed the stack.// (That statement is not always true because of the ABA problem)// Atomically replace top with next.if (top_ptr.compare_exchange_weak(ret_ptr, next_ptr)) {return ret_ptr;}// The stack has changed, start over.}}//// Pushes the object specified by obj_ptr to stack.//void Push(Obj* obj_ptr) {while (1) {Obj* next_ptr = top_ptr;obj_ptr->next = next_ptr;// If the top node is still next, then assume no one has changed the stack.// (That statement is not always true because of the ABA problem)// Atomically replace top with obj.if (top_ptr.compare_exchange_weak(next_ptr, obj_ptr)) {return;}// The stack has changed, start over.}}
};

考虑有两个线程并发的访问该队列。

初始时,栈顶元素是 A,A 指向 B,B 指向 C。

top --> A --> B --> C
  • Thread 1 执行 pop 操作,将栈顶元素 A 弹出,取出了top_ptr, 和 next_ptr后被中断。
Obj* ret_ptr = top_ptr;
if (ret_ptr == nullptr) return nullptr;// For simplicity, suppose that we can ensure that this dereference is safe// (i.e., that no other thread has popped the stack in the meantime).Obj* next_ptr = ret_ptr->next;

此刻,Thread 1里看到的是top_ptr等于A, next_ptr 等于B,问题其实就在这里了,保证top_ptr等于A时,并不能保证next_ptr等于B。

  • Thread 2 执行 pop 操作,将栈顶元素从 A 改为 B。
top --> B --> C
  • Thread 2 再次执行 pop 操作,将栈顶元素从 B 改为 C。
top --> C
  • Thread 2 执行 push 操作,将元素 A 推回到栈顶。
top --> A --> C
  • Thread 1 继续执行,执行 compare_exchange_weak(A, B),由于 top == ret,操作成功,栈顶元素变为了 B。
    此刻
top --> B(already delete)
  • Thread 1 访问栈顶元素,但是 B 已经被删除,这导致了 ABA 问题。
当从列表中删除一个项目并释放其内存后,如果再次分配一个新项目并将其添加到列表中,由于最近最常使用(MRU)的内存分配策略,新分配的对象通常会位于被删除对象的相同位置。
或者是在启用缓存机制时,重新分配的对象也有极大的概率是之前释放的对象。

ABA问题解决方案

在原有的内容上添加额外的“标签”或“戳记”位。例如,使用比较和交换(compare and swap)操作指针的算法可以使用地址的低位来表示指针成功修改的次数。因此,即使地址相同,下一次比较和交换操作也会失败,因为标签位不匹配。这种情况有时被称为ABAʹ,因为第二个A与第一个略有不同。这种带标签的状态引用也被用于事务内存(transactional memory)中。

在实现中,可以使用带标签的指针来解决ABA问题,其中指针的低位用于存储标签信息。然而,如果支持双宽比较和交换(double-width CAS),更常见的做法是使用单独的标签字段。

通过使用标签位,每次对共享数据进行操作时都会更新标签,即使地址相同,标签的变化也能够反映出对象的修改历史。这样,在进行比较和交换操作时,除了比较地址外,还需要比较标签位,从而更可靠地检测到对象的变化。

如果“标签”字段发生了环绕(wraparound),那么对抗ABA问题的保证就不再有效。然而,根据观察,在当前存在的CPU上,并且使用60位标签,只要程序的生命周期(即在不重新启动程序的情况下)限制在10年内,就不会发生环绕;此外,有人认为,为了实际目的,通常只需拥有40-48位的标签来确保不会发生环绕。由于现代CPU(特别是所有现代x64 CPU)倾向于支持128位的CAS(比较和交换)操作,这可以提供对抗ABA问题的可靠保证。

当使用128位CAS操作时,除了存储指针地址外,还可以存储一个更大的标签值。因为标签位数更多,所以即使在长时间运行的程序中,标签的环绕概率也非常低,几乎可以忽略不计。

通过使用128位CAS操作,并保留足够长度的标签位,可以提供对抗ABA问题的坚实保证。这意味着在多线程或并发环境中,即使对象的地址没有改变,只要标签发生变化,CAS操作也会失败,从而可以正确检测到对象的变化。这种方法在实践中被广泛采用,以确保数据的一致性和并发操作的正确性。

所谓的版本号、标记基本都是采用这个原理。

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

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

相关文章

Leetcode每日一题

https://leetcode.cn/problems/binary-tree-preorder-traversal/ 这道题目需要我们自行进行创建一个数组&#xff0c;题目也给出我们需要自己malloc一个数组来存放&#xff0c;这样能达到我们遍历的效果&#xff0c;我们来看看他的接口函数给的是什么。 可以看到的是这个接口函…

说说webpack中常见的loader?解决了什么问题?

在Webpack中&#xff0c;Loader是用于处理各种文件类型的模块加载器&#xff0c;它们用于对文件进行转换、处理和加载。常见的Loader解决了以下问题&#xff1a; 处理 JavaScript 文件&#xff1a;Babel Loader用于将最新的JavaScript语法转译为浏览器兼容的版本&#xff0c;以…

5_CSS三大特性盒子模型

第5章-盒子模型【比屋教育】 本课目标&#xff08;Objective&#xff09; 掌握CSS三大特性理解什么是盒子模型掌握内边距padding的用法掌握外边距margin的用法 1. CSS的层叠&#xff0c;继承&#xff0c;优先级 1.1 CSS层叠 层叠&#xff1a;是指多个CSS样式叠加到同一个元…

Web(8)SQL注入

Web网站&#xff08;对外门户&#xff09; 原理&#xff1a;not>and>or(优先级) 一.低级注入 order by的作用是对字段进行排序&#xff0c;如order by 5&#xff0c;根据第五个字段 进行排序&#xff0c;如果一共有4个字段&#xff0c;输入order by 5系统就会报错不 …

详细介绍开源固件-TF-A

什么是TF-A&#xff1f; TF-A&#xff08;Trusted Firmware-A&#xff09;是一种用于嵌入式系统的开源固件&#xff0c;而不是Linux的一部分。TF-A主要用于ARM架构的处理器和设备&#xff0c;它提供了一组安全和可信任的软件组件&#xff0c;用于引导和初始化系统。 如下是其…

GD32F30X-RT-Thread学习-线程管理

1. 软硬件平台 GD32F307E-START Board开发板MDK-ARM Keil 2.RT-Thread Nano 3.RT-Thread 内核学习-线程管理 ​ 在多线程操作系统中&#xff0c;可以把一个复杂的应用分解成多个小的、可调度的、序列化的程序单元&#xff0c;当合理地划分任务并正确地执行时&#xff0c;这…

qt可以详细写的项目或技术

1.QT 图形视图框架 2.QT 模型视图结构 3.QT列表显示大量信息 4.QT播放器 5.QT 编解码 6.QT opencv

Linux--RedHat--安装和配置C++环境

百度下载&#xff0c;安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1IgBfCCRxGYZ_PPiedad0xQ 提取码&#xff1a;ffff 下载后&#xff0c;建个目录&#xff0c;先解压好安装包&#xff01; &#xff08;两种方法&#xff09;执行如下命令&#xff1a; 参考…

Bypass open_basedir

讲解 open_basedir是php.ini中的一个配置选项&#xff0c;可用于将用户访问文件的活动范围限制在指定的区域。 假设open_basedir/var/www/html/web1/:/tmp/&#xff0c;那么通过web1访问服务器的用户就无法获取服务器上除了/var/www/html/web1/和/tmp/这两个目录以外的文件。…

Java——面试:String 和 StringBuffer 的区别?

相同点&#xff1a; String 和 StringBuffer&#xff0c;它们可以储存和操作字符串&#xff0c; 即包含多个字符的字符数据。 String 和 StringBuffer 的区别有以下几点&#xff1a; 1.String 类提供了数值不可改变的字符串。而 StringBuffer 类提供的字符串进行修改。 当你知…

洛谷 P8674 [蓝桥杯 2018 国 B] 调手表

文章目录 [蓝桥杯 2018 国 B] 调手表题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 题意解析CODE分析一下复杂度 [蓝桥杯 2018 国 B] 调手表 题目描述 小明买了块高端大气上档次的电子手表&#xff0c;他正准备调时间呢。 在 M78 星云&#xff0c;时间的计量…

JVM虚拟机:命令行查看JVM垃圾回收器的执行信息

在eclipse中打开命令行窗口 window->show view->Terminal 这样就打开了Terminal窗口&#xff0c;效果如下所示&#xff1a; java -XX:PrintCommandLineFlags -version 这个命令可以查看一些配置信息&#xff0c;其中最重要的配置信息就是&#xff0c;当前使用的G1回收器…

什么是漏洞扫描

漏洞扫描是指基于漏洞数据库&#xff0c;通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测&#xff0c;发现可利用漏洞的一种安全检测的 行为&#xff0c;也是一类重要的网络安全技术。它和防火墙、入侵检测系统互相配合&#xff0c;能够有效提高网络的安全性…

键盘打字盲打练习系列之成为大师——5

一.欢迎来到我的酒馆 盲打&#xff0c;成为大师&#xff01; 目录 一.欢迎来到我的酒馆二.关于盲打你需要知道三.值得收藏的练习打字网站 二.关于盲打你需要知道 盲打系列教程&#xff0c;终于写到终章了。。。一开始在看网上视频&#xff0c;看到up主熟练的打字技巧&#xff…

LabVIEW与Tektronix示波器实现电源测试自动化

LabVIEW与Tektronix示波器实现电源测试自动化 在现代电子测试与测量领域&#xff0c;自动化测试系统的构建是提高效率和精确度的关键。本案例介绍了如何利用LabVIEW软件结合Tektronix MDO MSO DPO2000/3000/4000系列示波器&#xff0c;开发一个自动化测试项目。该项目旨在自动…

javascript中Reflect是什么?三分钟初识

目录 1. Reflect是什么&#xff1f;2. 为什么会出现Reflect&#xff1f;3. 需要怎么去使用Reflect&#xff1f;4. 最终的结果解决什么&#xff1f;5. 使用的注意点6. 常用的技巧 Reflect是Javascript中的一个内置对象&#xff0c;它提供了一组用于操作对象的方法&#xff0c;可…

Spring - BeanFactory和FactoryBean的理解

BeanFactory是什么&#xff1f; BeanFactory是Spring 容器的根接口&#xff0c;它是IOC的基本容器&#xff0c;负责管理和加载Bean&#xff0c;它为具体的IOC容器提供了最基本的规范&#xff0c;比如DefaultListableBeanFactory和ConfigurableBeanFactory&#xff0c;BeanFact…

《C++新经典设计模式》之第17章 中介者模式

《C新经典设计模式》之第17章 中介者模式 中介者模式.cpp 中介者模式.cpp #include <iostream> #include <map> #include <memory> using namespace std;// 中介者封装一系列的对象交互 // 4种角色 // Mediator&#xff08;抽象中介者类&#xff09;&#x…

MYSQL练题笔记-高级查询和连接-指定日期的产品价格

这依旧是中等题&#xff0c;想了好久&#xff0c;终于理解了很开心&#xff01; 一、题目相关内容 1&#xff09;相关的表和题目 2&#xff09;帮助理解题目的示例&#xff0c;提供返回结果的格式 二、自己初步的理解 题目是找出2019-08-16 时全部产品的价格&#xff0c;所以…

数字化时代的到来,IT运维产业正在发生深刻的变革

IT运维产业是随着信息技术的发展而产生的&#xff0c;它涵盖了从硬件到软件、从应用到数据、从终端到云端等各个方面的维护和管理。随着数字化时代的到来&#xff0c;IT运维产业正在发生深刻的变革。其中&#xff0c;大数据技术的广泛应用和数据资源的日益丰富&#xff0c;正在…