关于golang:Go-为什么不支持可重入锁

8次阅读

共计 1342 个字符,预计需要花费 4 分钟才能阅读完成。

大家好,我是煎鱼。

程序里的锁,是很多小伙伴在写分布式应用时用的最多的一个利器之一。

应用 Go 的同学里,绝大部分都有其余语言的教训,就会对其中一点有纳闷,那就是 Go 里的锁,居然不反对可重入

为此,明天煎鱼带大家一起来理解这里的设计考量,看看为什么。

可重入锁

如果对曾经上锁的一般互斥锁进行“加锁”操作,其后果要么失败,要么会阻塞至解锁。

锁的场景如下:

  • 在加锁上:如果是可重入互斥锁,以后尝试加锁的线程如果就是持有该锁的线程时,加锁操作就会胜利。
  • 在解锁上:可重入互斥锁个别都会记录被加锁的次数,只有执行雷同次数的解锁操作才会真正解锁。

简略来讲,可重入互斥锁是互斥锁的一种,同一线程对其屡次加锁不会产生死锁,又或是导致阻塞。

不同语言间实现可能或多或少有些区别,但大体意思差不多。

请你想一下,Go 是怎么样的呢?

Go 反对状况

咱们看到以下这个 Go 互斥锁例子:

var mu sync.Mutex

func main() {mu.Lock()
    mu.Lock()}

这段 Go 程序会阻塞吗?不会,会报以下谬误:

fatal error: all goroutines are asleep - deadlock!

Go 显然是不反对可重入互斥锁的。

官网回复

Go 设计准则

在工程中应用互斥的根本原因是:为了爱护不变量,也能够用于爱护内、内部的不变量。

基于此,Go 在互斥锁设计上会恪守这几个准则。如下:

  • 在调用 mutex.Lock 办法时,要保障这些变量的不变性放弃,不会在后续的过程中被毁坏。
  • 在调用 mu.Unlock 办法时,要保障:

    • 程序不再须要依赖那些不变量。
    • 如果程序在互斥锁加锁期间毁坏了它们,则须要确保曾经复原了它们。

不反对的起因

讲了 Go 本人的设计准则后,那为什么不反对可重入呢?

其实 Russ Cox 于 2010 年在《Experimenting with GO》就给出了回答,认为递归(又称:重入)互斥是个坏主意,这个设计并不好。

咱们能够联合官网的例子来了解。

如下:

func F() {mu.Lock()
        ... do some stuff ...
        G()
        ... do some more stuff ...
        mu.Unlock()}

func G() {mu.Lock()
        ... do some stuff ...
        mu.Unlock()}

在上述代码中,咱们在 F 办法中调用 mu.Lock 办法加上了锁。如果反对可重入锁,接着就会进入到 G 办法中。

此时就会有一个致命的问题,你 不晓得 FG 办法加锁后是不是做了什么事件,从而导致毁坏了不变量,毕竟顺手起几个协程做点好事,也是齐全可能的。

这对于 Go 是无奈承受的,可重入的设计 违反了后面所提到的设计理念,也就是:“要保障这些变量的不变性放弃,不会在后续的过程中被毁坏”。

基于上述起因,Go 官网团队抉择了没有反对该项个性。

总结

Go 互斥锁没有反对可重入锁的设计,也是喜爱的大道至简的思路了,可能的烦扰比拟多,不如间接简略的来。

你在工作过程中有没有相似的纳闷呢,欢送大家在评论区留言和交换:)

若有任何疑难欢送评论区反馈和交换,最好的关系是相互成就 ,各位的 点赞 就是煎鱼创作的最大能源,感激反对。

文章继续更新,能够微信搜【脑子进煎鱼了】浏览,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言能够看 Go 学习地图和路线,欢送 Star 催更。

正文完
 0