go 并发模型 之 sync -- Mutex (四)

        


前言

前面的内存模型的章节里讲到  内存屏障

barrier 指令要求所有对内存的操作都必须要“扩散”到 memory 之后才能继续执行其他对 memory 的操作。

因此,我们可以用高级点的 atomic compare-and-swap,或者直接用更高级的锁,通常是标准库提供。


一、实现原理

实现模式

    Barging., Handsoff, Spinning

Barging: 这种模式是为了提高吞吐量,当锁被释放时,它会唤醒第一个等待者,然后把锁给第一个等待者或者给第一个请求锁的人。 提升吞吐量

        

 Handsoff:

当锁释放时候,锁会一直持有直到第一个等待者准备好获取锁。它降低了吞吐量,因为锁被持有,即使另一个 goroutine 准备获取它。

一个互斥锁的 handsoff 会完美地平衡两个goroutine 之间的锁分配,但是会降低性能,因为它会迫使第一个 goroutine 等待锁 

Spinning:自旋在等待队列为空或者应用程序重度使用锁时效果不错。Parking 和 Unparking goroutines 有不低的性能成本开销,相比自旋来说要慢得多。

        饥饿模式:Go 1.9 通过添加一个新的饥饿模式来解决下面例子中问题,该模式将会在释放时候触发 handsoff。所有等待锁超过一毫秒的 goroutine(也称为有界等待)将被诊断为饥饿。当被标记为饥饿状态时,unlock 方法会 handsoff 把锁直接扔给第一个等待者。 在饥饿模式下,自旋也被停用,因为传入的goroutines 将没有机会获取为下一个等待者保留的锁。

      实现原理

        先讲原理在讲源码。 只讲源码的都是耍流氓!

      lock

调用lock方法时

1.当锁处于初始的状态会直接调用CAS的方法获取锁 

Fast path: grab unlocked mutex.

  获取成功执行 race 检测 

 获取失败执行2

2.加锁失败会进入 lockSlow 函数        

   2.1 首先会判断是否可以进入自旋状态 如果可以进入自旋 最多自旋4次

  2.2 自旋结束计算当前锁的状态

  2.3 尝试根据CAS 获取锁 如果没有获取到就调用 runtime_SemacquireMutex 方法休眠当前 goroutine 

2.4 休眠结束 goroutine  会被唤醒  会先判断当前是否处在饥饿状态 

        2.4.1 如果当前 goroutine 超过 1ms 都没有获取到锁就会进饥饿模式

                设置唤醒和饥饿标记,重置迭代次数重新执行获取锁的循环

        2.4.1 如果处于饥饿模式就获

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值