现在主流的多处理器架构都在硬件水平上提供了对并发同步的支持。

今天我们讨论两个很重要的硬件同步指令:Test-and-Set和Compare-and-Swap

Test and Set

一个Test-and-Set(TAS)指令包括两个子步骤,把给定的内存地址设置为1,然后返回之前的旧值。

这两个子步骤在硬件上实现为一个原子操作,执行期间不会被其他处理器打断。

(一个CPU可以使用诸如Dual-port RAM电子原件提供的TAS指令,此外,CPU自身也可以提供CAS指令)

值得注意的是,TAS指令是在1位(bit)上实现,这限制了变量非0即1,不会有其他值,并且TAS总是把变量设置为1。

可见,TAS生而为自旋锁,下面是使用TAS实现自旋锁的伪代码[2]:

lock = 0 //shared state
while(test_and_set(lock)==0){ //try lock
//do nothing
}
// 临界区代码
lock = 0 //release

当第一个线程执行这段代码时,TAS指令会立即把lock设置为1,并返回0 ,线程退出while循环进入临界区。

如果另一个线程尝试进入临界区,TAS会把lock设置为1,但是也会返回1(由第一个线程的TAS指令设置为1),

此时第二个线程会一直while循环(忙等待),直到第一个线程退出临界区代码,执行了lock=0,即释放了锁。

这种通过while-loop等待获取锁的实现称为自旋锁(spin lock)。

Compare and Swap

compare-and-swap(CAS)指令和TAS指令类似,但是比TAS要更复杂。

与TAS只有一个参数不同,CAS指令需要三个参数,一个内存位置(V)、一个期望旧值(A)、一个新值(B)。

CAS指令的执行过程:

1.比较内存V的值是否与A相等?
2.如果相等,则用新值B替换内存位置V的旧值
3.如果不相等,不做任何操作。
4.无论哪个情况,CAS都会把内存V原来的值返回。

伪代码:

int CAS(int *ptr,int oldvalue,int newvalue)
{
int temp = *ptr;
if(*ptr == oldvalue)
*ptr = newvalue
return temp;
}

以上过程在CAS指令中是原子操作。

CAS支持32bit/64bit的数据类型,这使得CAS能够实现一些更复杂的自旋锁。

使用CAS实现线程安全的数据结构。

我们使用CAS实现一个并发的平衡二叉搜索树。[1]

基本思路是,所有的更新操作都要在二叉树的副本上进行,更新完成后,使用CAS指令把新的根节点引用替换旧的引用。

//共享变量
root = pointer to the root of the tree
//插入操作
do
old_root = root
new_root = new Tree
# copy old_root into new_root
# do insertion into new_root
until compare_and_swap (root, old_root, new_root) == old_root
平衡操作:
do
old_root = root
new_root = balanced_copy_of (old_root)
until compare_and_swap (root, old_root, new_root) == old_root

如果并行的执行平衡操作和插入操作,插入操作完成后会把二叉树的根节点指向新的引用。

等到平衡操作完成后,compare_and_swap将会失败,因为此时根节点指向了插入操作产生的新地址,不再等于old_root,

平衡操作会重复循环执行,直到成功更新根节点。

同样的,如果平衡操作先于插入操作完成,插入操作的CAS指令也会失败(根节点已指向平衡操作产生的新地址),然后插入操作重复循环,直到成功。

基于CAS指令可以实现基础的信号量、互斥量之外,还可以实现更复杂的lock-free和wait-free算法。

延伸阅读:

1.康奈尔大学操作系统课件:Architectural support for synchronization

2.wiki:Test-and-Set指令

3.wiki:Compare-and-swap指令

4.TAS vs CAS

硬件对同步的支持-TAS和CAS指令的更多相关文章

  1. Confluence 6 从外部目录中同步数据支持的目录类型

    针对一些特定的用户目录类型,Confluence 在系统的数据库中保存了目录的缓存信息(用户和用户组),这样能够让系统更快速的访问用户和用户组数据.一个数据同步的进程将会间歇性的在系统中运行来将远程的 ...

  2. CAS指令

    原文链接:https://www.jianshu.com/p/00edb3d74a33   CAS是CPU的一条指令,其具有原子性,原子性是由CPU硬件层面保证的.   CAS原语有三个操作数--内存 ...

  3. 从ObjectPool到CAS指令

    相信最近看过我的文章的朋友对于Microsoft.Extensions.ObjectPool不陌生:复用.池化是在很多高性能场景的优化技巧,它能减少内存占用率.降低GC频率.提升系统TPS和降低请求时 ...

  4. 【PC桌面软件的末日,手机移动端App称王】写在windows11支持安卓,macOS支持ios,龙芯支持x86和arm指令翻译

    面对这场突如其来的变革,作为软件开发者,应该如何选择自己今后的发展方向?桌面软件开发领域还有前景吗? 起源 自从苹果发布m1处理器,让自家Mac支持IOS移动端app运行之后,彻底打破了移动端app和 ...

  5. CAS(硬件CPU同步原语)

    CAS有3个操作数.内存值V,旧的预约值A,要修改后的新值B.当且仅当预期值A和预期值V相同时,将内存值V修改为新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做. 应用1. ...

  6. 定时自动同步文件,支持多文件夹同步,支持过滤文件和文件夹,解决FileSystemWatcher多次文件触发事件(源码)

    博客园里面有很多同步工具和软件,关于FileSystemWatcher类解释的也很多,但收集了很多文章后,感觉没好的方法,自己没事写了一个定时文件同步,借鉴了很多博客园朋友的东西: 上主菜: 配置文件 ...

  7. Netty的并发编程实践3:CAS指令和原子类

    互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能的额外损耗,因此这种同步被称为阻塞同步,它属于一种悲观的并发策略,我们称之为悲观锁.随着硬件和操作系统指令集的发展和优化,产生了非阻塞同步,被称为 ...

  8. 《java并发编程实战》读书笔记12--原子变量,非阻塞算法,CAS

    第15章 原子变量与非阻塞同步机制 近年来,在并发算法领域的大多数研究都侧重于非阻塞算法,这种算法用底层的原子机器指令(例如比较并交换指令)代替锁老确保数据在并发访问中的一致性. 15.1 锁的劣势 ...

  9. .NET机器学习 ML.NET 1.4预览版和模型生成器更新

    ML.NET 是面向.NET开发人员的开源和跨平台机器学习框架. ML.NET  还包括Model Builder  (一个简单的UI工具)和  CLI  ,使用自动机器学习(AutoML)构建自定义 ...

随机推荐

  1. Shell编程案例:修改运维脚本输出效果

    1. 需求:每日运维检查脚本dailymonitor.sh显示对服务器测试结果,其中命令 zabbix_get -s 192.168.111.21 -p 10050 -k "net.tcp. ...

  2. (Java实现) 友好城市

    1263:[例9.7]友好城市 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 1867 通过数: 1032 [题目描述] Palmia国有一条横贯东西的大河,河有笔直的南北两岸, ...

  3. java实现第二届蓝桥杯地铁换乘(C++)

    地铁换乘. 为解决交通难题,某城市修建了若干条交错的地铁线路,线路名及其所属站名如stations.txt所示. 线1 苹果园 .... 四惠东 线2 西直门 车公庄 .... 建国门 线4 .... ...

  4. 启动appium server时打印日志时间

    在调试脚本的时候想看查找元素和执行命令花了多少时间,我们可以在启动appium server的时候加上启动参数,实现我们的需求. 1)输入:appium h,可以查看appium提供的启动参数有哪些. ...

  5. OC语言

    // // main.m // 测试题05 // // Created by yang sanchao on 9/12/15. // Copyright (c) 2015 yang sanchao. ...

  6. 学习Redis好一阵了,我对它有了一些新的看法

    前言 本篇文章不是一篇具体的教程,我打算记录一下自己对Redis的一些思考.说来惭愧,我刚接触Redis的时候只是简单地使用了一下,背了一些面试题,就在简历上写下了Redis这个技能点. 我们能在网络 ...

  7. DevOps系列——Jenkins/Gitlab自动打包部署

    前面只说了DevOps的两个基础组件Jenkins和GitLab,客官也不要着急,我们玩就玩的深入一点,Gitlab和Jenkins的各种配置和 插件很多,也够啃一阵子的,不要照着操作一通就感觉万事大 ...

  8. URL 链接中的 UTM参数何定义?

    浏览网页或者点击广告的时候,细心的朋友们或者有关注浏览器地址栏的 URL 链接时,一定会发现 utm_source 或者与其类似的链接,那么链接中的这个UTM参数有什么用呢? UTM 为“Urchin ...

  9. mtail 调试

    mtail 调式 mtail 不会采集当前accesslog 内容以前的内容,只有当你启动mtail后,去访问你的监控tomcat,有新的access 日志刷入localhost_access_log ...

  10. DockerFile构建镜像和Docker仓库

    利用commit理解镜像构成 注意: docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现 场等.但是,不要使用 docker commit 定制镜像,定制镜像应该 ...