并发与锁

栏目: IT技术 · 发布时间: 7年前

内容简介:AQS整体结构锁的获取过程获取失败挂起的过程

并发与锁

JUC AQS

AQS整体结构

锁的获取过程

  • CAS rote 回转数的问题

获取失败挂起的过程

释放锁唤醒等待的过程

  • 如何防止丢失唤醒

    入队时不能“贪睡”,找可靠等待者并让他叫醒自己,不在进而就获取锁,其他所有情况都告诉标记前驱别忘了叫醒自己

    这就够了吗,显然还不行;满足自己去“睡”的条件的check和“睡”显然不是一个原子操作。在check后和“睡着”前如果条件变了就没人叫醒

    unpark和park早就预防相关问题,猜想内部是有变量记忆了上次的操作后状态,同时基于操作系统提供的锁保证了原子性

  • 如何防止惊群问题

    锁的唤醒通常是有唤醒一个等待线程和唤醒全部等待线程的;通常在编程条件下如果想减少全部唤醒的引发不必要的竞争时,还要注意虚假

    唤醒问题,被唤醒的线程如果条件不满足条件释放锁后造成唤醒链脱节的问题。而这种情况又不能简单在自己释放锁前去唤醒其他等待者。

    所以比如在leader-follower模式中,如果leader线程只在原leader线程离任时唤醒任意一个等待线程时,则当线程都在follower模式

    时因为没有唤醒者陷入停机状态,所以在每次完成工作时还要尝试自荐为leader。如果leader在离任时唤起其他所有线程显然时惊群的。

AQS小结

  • 双检锁的简单优化
  • 流言:cas+clh队列语义上等价于锁

    线程阻塞于唤醒的闭合性无法满足,需要借助cpu指令中的屏蔽中断与禁止抢占保证调度切换的原子性

从CAS到内存屏障再到缓存一致性协议

  • volatile happens-before

    如果a线程先写入新值,b线程紧接着(赋值后隔一个时钟周期,这样可以使得无论是lock前缀的指令排空store buffer

    并且失效其他处理器的对于缓存得以执行完,或者时钟中断引发store buffer排空进而触发缓存一致性同步)去读就能

    最新值,不过由于需要间隔一个时钟周期,看似违反happens-before;不过由于紧接着是lock的情况在紧接着的时钟

    周期里由于lock触发缓存一致性同步会失效该数据项的旧值所以不会有问题,时钟中断的间接触发缓存同步也类似。

  • unsafe 源码

https://github.com/dmlloyd/openjdk/blob/jdk/jdk/src/hotspot/share/prims/unsafe.cpp

  • CAS 指令与总线锁 CMPXCHG16B
  • 内存屏障与缓存一致性协议
  • 编译器优化、cpu乱序执行【关于体系结构只针对X86-64其他乱序自由度更大的暂不考虑,料想其原理是类似的】

冒险:

数据冒险

结构冒险

控制冒险(分支冒险)

MESI、MOSI、MESIF

一图胜过千言(待添加),

硬件结构: 写缓存的读取优先与L1cache,写合并WC优化;写回缓存WB,写穿透缓存WT,

写失效WI,经验表明写失效,更节约带宽

写更新WU,看起来快,有时候是不必要的如果更新每个缓存比起一条失效指令代价大许多;

更新可能是断续多次而失效只要一次,而且缓存行内容的大小比缓存地址大位宽大不少

X86-64一致性高,LoadLoad Memory Barrier是因为读屏障会强制等待Invalidate Queue清空才继续执行,

这样可以消除其引发的读乱序问题

  • 缓存一致性协议提供了缓存一致性的必要的手段和机制,内存屏障是通过简单的抑制乱序以及对这些手段和机制的利用

    进而达到缓存一致的对外表现。这里提现硬件的对外复杂度的隔离封装,对外暴露了简单的接口,内部实现像水面下的

    冰山。

缓存一致性协议显然在硬件上有锁的语义的

loadload

loadstore

storeload (x86 TSO 唯一乱序的地方)

storestore

Synchronized

  • 对象头

  • 锁升级

  • 安全点及延申

    精确式GC、安全点调度以及协程调度 java 与golang

Futex

Futex是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享 的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不 用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。 Linux从2.5.7开始支持Futex。
  • 自旋锁

    内核的基本锁之一

  • 自旋优化(jdk9与自旋提示)

自旋是在循环中不断重试检测条件变量的值,这样为了保证可见性,就需要不断的同步缓存,造成很多不必要的开销。

  • RCU锁

    包含的数据通常都是指针类型的,每个核上都发生过调度就说明如果其他核在该rcu锁的读临界区,完成一轮调度后(读临界区不可抢占)

    如果再有新的线程可见的数据是新的老版本的可以释放了。如果是可抢占的RCU就需要在锁定开头和释放的结尾维护一个计数器。

  • 屏蔽中断与禁止抢占

锁的构成要素

>cas
>等待队列
>屏蔽中断禁止抢占的原子调度上下文的切换

理解与体会

  • 不总结不准备就会拔剑四顾心茫然

  • 读写时序

  • 控制流与数据流的等价性

  • 几种并发模型 actor、CSP、CPS/CallCC
  • 锁的本质问题是时序问题,调度可以解决时序问题,调度问题从cpu角度看又是执行权的问题,锁是保护了数据,锁是通过限制代码的执行来保护数据的。

mesi为什么可以保证一致性对分布式环境缓存一致性有什么启示

首先总线的作用是巨大的,他保证了多核乃至多路cpu间的缓存一致性

分布式环境下由于没有统一的总线,缺少收敛的协调控制。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具