go为什么不支持可重入锁

可重入锁是什么

public class Test{
     Lock lock = new Lock();
     public void methodA(){
         lock.lock();
         ...........;
         methodB();
         ...........;
         lock.unlock();
     }
     public void methodB(){
         lock.lock();
         ...........;
         lock.unlock();
     }
}

当A方法获取lock锁去锁住一段需要做原子性操作的B方法时,如果这段B方法又需要锁去做原子性操作,那么A方法就必定要与B方法出现死锁。这种会出现问题的重入一把锁的情况,叫不可重入锁。

A方法需要等B方法执行完才能解锁,但是B方法想执行完代码又必须要lock锁来加锁。A的锁未解锁前,其他代码块无法使用此锁来加锁。这是由这个不可重入锁决定的。

为什么Go没有可重入锁

如果当你的代码需要重入锁时,那就说明你的代码有问题了,我们正常写代码时,从入口函数开始,执行的层次都是一层层往下的,如果有一个锁需要共享给几个函数,那么就在调用这几个函数的上面,直接加上互斥锁就好了,不需要在每一个函数里面都添加锁,再去释放锁。


func call(){
  F()
  G()
}

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

func g() {
     ... do some stuff ...
}

func G() {
     mu.Lock()
     g()
     mu.Unlock()
}

这样不仅避免了死锁,而且还对代码进行了解耦。这样的代码按照作用范围进行了分层,就像金字塔一样,上层调用下层的函数,越往上作用范围越大;各层有自己的锁。

总结:Go语言中完全没有必要使用可重入锁,如果我们发现我们的代码要使用到可重入锁了,那一定是我们写的代码有问题了,请检查代码结构,修改他!!!

在单线程的测试中,无法发现bug。可重入锁无法保护invariant,是可能导致大问题的。

使用可重入锁是一种彻彻底底的错误,它是bug的温床


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!