比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预知性产生的数据不一致问题。 该操作通过将内存中的值与指定数据进行比较,当数值一样时将内存中的数据替换为新的值。

概述[编辑]

一个CAS操作的过程可以用以下c代码表示: [1]

1 int cas(long *addr, long old, long new)
2 {
3 /* Executes atomically. */
4 if(*addr != old)
5 return 0;
6 *addr = new;
7 return 1;
8 }

在使用上,通常会记录下某块内存中的旧值,通过对旧值进行一系列的操作后得到新值,然后通过CAS操作将新值旧值进行交换。如果这块内存的值在这期间内没被修改过,则旧值会与内存中的数据相同,这时CAS操作将会成功执行 使内存中的数据变为新值。如果内存中的值在这期间内被修改过,则一般[2]来说旧值会与内存中的数据不同,这时CAS操作将会失败,新值将不会被写入内存。

应用[编辑]

在应用中CAS可以用于实现无锁数据结构,常见的有无锁队列(先入先出)[3] 以及无锁堆(先入后出)。对于可在任意位置插入数据的链表以及双向链表,实现无锁操作的难度较大。[4]

ABA问题[编辑]

ABA问题是无锁结构实现中常见的一种问题,可基本表述为:

  1. 进程P1读取了一个数值A
  2. P1被挂起(时间片耗尽、中断等),进程P2开始执行
  3. P2修改数值A为数值B,然后又修改回A
  4. P1被唤醒,比较后发现数值A没有变化,程序继续执行。

对于P1来说,数值A未发生过改变,但实际上A已经被变化过了,继续使用可能会出现问题。在CAS操作中,由于比较的多是指针,这个问题将会变得更加严重。试想如下情况:

   top
|
V
0x0014
| Node A | --> | Node X | --> ……

有一个堆(先入后出)中有top和节点A,节点A目前位于堆顶top指针指向A。现在有一个进程P1想要pop一个节点,因此按照如下无锁操作进行

pop()
{
do{
ptr = top; // ptr = top = NodeA
next_prt = top->next; // next_ptr = NodeX
} while(CAS(top, ptr, next_ptr) != true);
return ptr;
}

而进程P2在执行CAS操作之前打断了P1,并对堆进行了一系列的pop和push操作,使堆变为如下结构:

   top
|
V
0x0014
| Node C | --> | Node B | --> | Node X | --> ……

进程P2首先pop出NodeA,之后又Push了两个NodeB和C,由于内存管理机制中广泛使用的内存重用机制,导致NodeC的地址与之前的NodeA一致。

这时P1又开始继续运行,在执行CAS操作时,由于top依旧指向的是NodeA的地址(实际上已经变为NodeC),因此将top的值修改为了NodeX,这时堆结构如下:

                                   top
|
0x0014 V
| Node C | --> | Node B | --> | Node X | --> ……

经过CAS操作后,top指针错误的指向了NodeX而不是NodeB。

实现[编辑]

CAS操作基于CPU提供的原子操作指令实现。对于Intel X86处理器,可通过在汇编指令前增加LOCK前缀来锁定系统总线,使系统总线在汇编指令执行时无法访问相应的内存地址。而各个编译器根据这个特点实现了各自的原子操作函数。[5]

  • C语言C11的头文件<stdatomic.h>。由GNU提供了对应的__sync系列函数完成原子操作。 [6][7]
  • C++11,STL提供了atomic系列函数。[8][7]
  • JAVA,sun.misc.Unsafe提供了compareAndSwap系列函数。[9]
  • C#,通过Interlocked方法实现。[10]
  • Go, 通过import "sync/atomic"包实现。[11]
  • Windows,通过Windows API实现了InterlockedCompareExchangeXYZ系列函数。[12][7]

比较并交换(compare and swap, CAS)的更多相关文章

  1. Compare and Swap [CAS] 算法

    一个Java 5中最好的补充是对原子操作的支持类,如AtomicInteger,AtomicLong等.这些类帮助你减少复杂的(不必要的)多线程代码,实际上只是完成一些基本操作,如增加或减少多个线程之 ...

  2. Compare and Swap(CAS)

    CAS(Compare and Swap)是个原子操作.拿到一个新值后,CAS将其与内存中的值进行比较,若内存中的值和这个值不一样,则将这个值写入内存,否则,不做操作.在Java的 java.util ...

  3. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  4. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

  5. Java并发基础之Compare And Swap/Set(CAS)

    什么是 CAS?CAS(Compare And Swap/Set)比较并交换, CAS 算法的过程是这样:它包含 3 个参数CAS(V,E,N). V 表示待更新的变量(内存值), E 表示预期值(旧 ...

  6. CAS(Compare and Swap)理解

    什么叫CAS(Compare and Swap)?  硬件同步原语!! 什么蛋疼的名字,一般人很难理解.根据英文全称翻译==比较与交换,这个名字大致还能理解一点,目前先暂且这么理解吧. 有啥用处? 对 ...

  7. Java多线程和并发(十一),CAS(Compare and Swap)

    目录 1.CAS简介 2.CAS多数情况下对开发者来说是透明的 3.CAS缺点 十一.CAS(Compare and Swap) Synchronized直观意义上是一种悲观锁 cas则是乐观锁的一种 ...

  8. 无锁机制----比较交换CAS Compare And Swap

    一.锁与共享变量 加锁是一种悲观的策略,它总是认为每次访问共享资源的时候,总会发生冲突,所以宁愿牺牲性能(时间)来保证数据安全. 无锁是一种乐观的策略,它假设线程访问共享资源不会发生冲突,所以不需要加 ...

  9. 面试:为了进阿里,又把并发CAS(Compare and Swap)实现重新精读一遍

    该系列文章已收录在公众号[Ccww技术博客],原创技术文章第一时间推出 前言 在面试中,并发线程安全提问必然是不会缺少的,那基础的CAS原理也必须了解,这样在面试中才能加分,那来看看面试可能会问那些问 ...

  10. CAS(Compare and Swap)无锁算法-学习笔记

    非阻塞同步算法与CAS(Compare and Swap)无锁算法 这篇问题对java的CAS讲的非常透彻! 锁的代价 1. 内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的 ...

随机推荐

  1. 编码技巧 --- 使用dynamic简化反射

    引言 dynamic 是 Framework 4.0 就出现特性,它的出现让 C# 具有了弱语言类型的特性.编译器在编译的时候不再对类型进行检查,默认 dynamic 对象支持开发者想要的任何特性. ...

  2. CSDN这么公然爬取(piao qie)cnblogs的文章,给钱了吗?

    在CSDN网站经常看到有博客转载cnblogs的文章,开始还以为是网友自行转载,后来才发现,这些所谓的转载应该都是机器爬取(piao qie)过去的.不知道cnblogs对此怎么看. 下面看看几个示例 ...

  3. CPU摸鱼被抓,上了一个新技术!

    我叫阿Q,是CPU一号车间里的员工,我所在的这个CPU足足有8个核,就有8个车间,干起活来杠杠滴. 我们CPU的任务就是执行程序员编写的程序,只不过程序员编写的是高级语言代码,而我们执行的是这些代码被 ...

  4. AcWing 4797. 移动棋子题解

    算出数值为 \(1\) 的点离 \((3, 3)\) 的距离即可. #include <iostream> #include <cstring> #include <al ...

  5. Weblogic T3协议反序列化命令执行漏洞(CVE-2018- 2628)复现

    好久没发新文章了,躲懒了,是时候该更新一篇了,这一篇是关于WebLogic T3协议反序列化命令执行漏洞(CVE-2018- 2628)的复现,该漏洞是weblogic的经典漏洞,而网上有关的复现稍显 ...

  6. Gin中间件开发

    Gin是一个用Go语言编写的Web框架,它提供了一种简单的方式来创建HTTP路由和处理HTTP请求.中间件是Gin框架中的一个重要概念,它可以用来处理HTTP请求和响应,或者在处理请求之前和之后执行一 ...

  7. 【pytorch】ResNet源码解读和基于迁移学习的实战

    "工欲善其事,必先利其器",掌握ResNet网络有必要先了解其原理和源码.本文分别从原理.源码.运用三个方面出发行文,先对ResNet原理进行阐述,然后对pytorch中的源码进行 ...

  8. Redis专题-队列

    Redis专题-队列 首先,想一想 Redis 适合做消息队列吗? 1.消息队列的消息存取需求是什么?redis中的解决方案是什么? 无非就是下面这几点: 0.数据可以顺序读取 1.支持阻塞等待拉取消 ...

  9. 关于 Llama 2 的一切资源,我们都帮你整理好了

    Llama 2 是一个由 Meta 开发的大型语言模型,是 LLaMA 1 的继任者.Llama 2 可通过 AWS.Hugging Face 获取,并可以自由用于研究和商业用途.Llama 2 预训 ...

  10. 只要学会这些AI工具,一个人就是一家营销咨询公司

    随着AI工具的不断涌现,您只需掌握市面上热门的AI工具,便可独自开展营销咨询公司.通过一系列AI工具,您可以为企业提供全案服务,收获丰厚回报. 例如,在协助一家美妆初创公司出海时,我们运用一系列AI工 ...