03|Mutex:4种易错场景大盘点

2020-10-16 晁岳攀/鸟窝
《Go 并发编程实战课》
课程介绍


讲述:安晓辉

时长:大小24.58M


你好,我是鸟窝。
上一讲,我带你一起领略了 Mutex 的架构演进之美,现在我们已经清楚 Mutex 的实现细节了。当前 Mutex 的实现貌似非常复杂,其实主要还是针对饥饿模式和公平性问题,做了一些额外处理。但是,我们在第一讲中已经体验过了,Mutex 使用起来还是非常简单的,毕竟,它只有 Lock 和 Unlock 两个方法,使用起来还能复杂到哪里去?
正常使用 Mutex 时,确实是这样的,很简单,基本不会有什么错误,即使出现错误,也是在一些复杂的场景中,比如跨函数调用 Mutex 或者是在重构或者修补 Bug 时误操作。但是,我们使用 Mutex 时,确实会出现一些 Bug,比如说忘记释放锁、重入锁、复制已使用了的 Mutex 等情况。那在这一讲中,我们就一起来看看使用 Mutex 常犯的几个错误,做到“Bug 提前知,后面早防范”。

常见的 4 种错误场景

我总结了一下,使用 Mutex 常见的错误场景有 4 类,分别是 Lock/Unlock 不是成对出现、Copy 已使用的 Mutex、重入和死锁。下面我们一一来看。

Lock/Unlock 不是成对出现

...

展开全文
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。

精选留言

  • Junes
    2020-10-16
    分享一个我觉得很有项目借鉴意义的PR吧:

    https://github.com/pingcap/tidb/pull/20381/files

    这个问题是在当前的函数中Lock,然后在调用的函数中Unlock。这种方式会导致,如果运行子函数时panic了,而外部又有recover机制不希望程序崩溃,就触发不到Unlock,引起死锁。

    PR中加了个recover处理,并且判断recover有error才Unlock,这是一种处理方法。

    理想的设计,是将子函数的Unlock挪到与Lock平级的代码,或者不进行recover处理,Let it panic后修复问题。但大型项目项目经常会因为逻辑错综复杂或者各种历史原因,不好改动吧,这种处理方式虽然不好看,但能解决问题,有时候也挺无奈的~
    展开
    
    40
  • Remember九离
    2020-10-18
    第三课代码整理:https://github.com/wuqinqiang/Go_Concurrency/tree/main/class_3

    作者回复: 赞。其他读者可以关注这位朋友的整理

    共 3 条评论
    12
  • iamjohnnyzhuang
    2020-11-01
    买这个课程本来没报多大希望,没想到看看几节下来太赞了,不仅说到了一些技术的实现细节,同时给出的让我们业务开发避免的经验、排查方法也十分有借鉴价值
    共 4 条评论
    11
  • buckwheat
    2020-10-16
    看了一眼tidb关于mutex的issue,发现大部问题都出现在Unlock的时机上面,尤其是涉及到多个锁的时候,把Lock和Unlock放到两个方法里面就非常容易出现这种情况。tidb出现data race的issue要比dead lock的要多的多。老师,业务复杂时,在涉及到链式加锁时有没有什么好的办法避免死锁呢?
    共 3 条评论
    6
  • 打奥特曼的小怪兽
    2020-10-16
    这个课程看起来很有意思
    
    5
  • 橙子888
    2020-10-16
    在 TiDB Pull requests 已经 closed 的搜索 deadlock 关键字发现好多,例如 https://github.com/pingcap/tidb/pull/500,问题的原因在于释放的位置有问题。
    共 1 条评论
    4
  • pony
    2020-10-24
    老师讲解的很仔细,对mutex使用错误场景都列举了
    补充点:Go语言核心36讲的解锁一个未加锁的mutex 导致的panic,无法被recover()捕获
    共 1 条评论
    4
  • 罗杰
    2020-10-19
    简单易懂 列举知名开源项目漏洞来对应自己的总结 太棒了👏
    
    3
  • gitxuzan
    2020-10-21
    有个地方不明白, 为什么源码里面需要用atomic 原子操作和直接赋值有什么区别

    作者回复: 这个可以等atomic那一讲出来再了解

    共 3 条评论
    2
  • Stony.修行僧
    2020-10-16
    活捉一只大佬,写的真好,感觉编程语言里面锁技术是精髓之一
    
    2
  • 阿牛
    2021-02-22
    Mutex常见四种错误场景
    1、Lock/Unlock不是成对出现
    2、Copy已使用的Mutex
    3、重入
    4、死锁
    
    1
  • Fan
    2020-12-23
    看了前三节,这门课写的太棒了。继续打卡。

    作者回复: 加油!!!

    共 2 条评论
    1
  • 科科
    2020-12-03
    大佬也有写错的时候,不能说完全避免问题,但一定要学习如何解决问题
    
    1
  • 消逝文字
    2020-11-09
    真是想不到,知名的开源项目里面居然也会有一些我们编码时常犯的低级错误
    
    1
  • 虫子樱桃
    2020-10-21
    跟这个很类似 https://medium.com/@bytecraze.com/recursive-locking-in-go-9c1c2a106a38
    
    1
  • roseduan
    2020-10-17
    将 Unlock 误写成了 Lock,哈哈哈,原来这些大佬也会犯低级错误
    
    1
  • 李金狗
    2021-08-27
    写了一个库 https://github.com/longlihale/goid 获取 goid 的欢迎大家使用~
    
    
  • 、荒唐_戏_
    2021-07-17
    docker 第二个锁问题,遇到相同的,当时排查了一天多。搞到凌晨一点,没搞定,第二天中午十一点发现依赖的同事开发的库有这个问题, 发现原因的时候想死的心都有了
    
    
  • Geek_7cc27c
    2021-01-29
    Tidb在用mutex的时候特意改成了defer 这种方式,https://github.com/pingcap/tidb/pull/19072,
    不过找了个比较老的issue,https://github.com/pingcap/tidb/pull/5171 ,lock和unlock还是没有统一用defer的方式,这个以后可能成为隐患吧。

    作者回复: 👍🏻

    
    
  • David
    2021-01-04
    您好老师,在设计可重入锁的时候,在lock方法中,
        // 延用mutex的加锁机制
        m.Mutex.Lock()
        atomic.StoreInt64(&m.owner, gid)
    这个地方有必要 使用atomic吗?
          

    其次,如果有必要,为什么 m.recursion = 1 不用了呢
    我个人认为,在锁里面,好像是没必要使用的吧
    展开

    作者回复: 第11行未加锁

    共 2 条评论
    