• golang锁机制


    Golang中如何避免死锁:加锁

    • 读写锁中的可读锁(sync.RWMutex 的 RLock())可以嵌套使用的。
    • 互斥锁(sync.Mutex 和 sync.RWMutex 的 Lock())是不可以互相嵌套的,且不可以与可读锁嵌套。

    之前我在读写锁和互斥锁上理解有偏差,认为读写锁与互斥锁是完全独立且相互对应的关系。现在理解为 互斥 只是一种特性。而把 sync.Mutex 叫作 全局锁, sync.RWMutex 叫作 读写锁

    全局锁 sync.Mutex,是同一时刻某一资源只能上一个锁,此锁具有排他性,上锁后只能被此线程使用,直至解锁。加锁后即不能读也不能写。全局锁是互斥锁,即 sync.Mutex 是个互斥锁。

    读写锁 sync.RWMutex ,将使用者分为读者和写者两个概念,支持同时多个读者一起读共享资源,但写时只能有一个,并且在写时不可以读。理论上来说,sync.RWMutex 的 Lock() 也是个互斥锁。

    踩坑点

    将上面的结论展开一下,更清晰得说(为避免理解偏差宁可唠叨一些):

    • sync.Mutex 的锁是不可以嵌套使用的。
    • sync.RWMutex 的 mu.Lock() 是不可以嵌套的。
    • sync.RWMutex 的 mu.Lock() 中不可以嵌套 mu.RLock()。(这是个注意的地方)

    否则,会 panic fatal error: all goroutines are asleep - deadlock!

    所以以下函数不会造成 panic:

    var l sync.RWMutex
    
    func readAndRead() { // 可读锁内使用可读锁
        l.RLock()
        defer l.RUnlock()
    
        l.RLock()
        defer l.RUnlock()
    }
    
    func main() {
        lockAndRead()
        time.Sleep(5 * time.Second)
    }

    而将 readAndRead 换为以下三种函数均会造成 panic:

    func lockAndLock() { // 全局锁内使用全局锁
        l.Lock()
        defer l.Unlock()
    
        l.Lock()
        defer l.Unlock()
    }
    
    func lockAndRead() { // 全局锁内使用可读锁
        l.Lock()
        defer l.Unlock() // 由于 defer 是栈式执行,所以这两个锁是嵌套结构
    
        l.RLock()
        defer l.RUnlock()
    }
    
    func readAndLock() { // 可读锁内使用全局锁
        l.RLock()
        defer l.RUnlock()
    
        l.Lock()
        defer l.Unlock()
    }

    注: 在 goroutine 中的 panic 不会影响主程序,所以在测试时要注意并不是没有 panic 输出就一定是没发生。

  • 相关阅读:
    《机器学习》周志华 习题答案8.5
    《机器学习》周志华 习题答案8.3
    《机器学习》周志华 习题答案7.3
    《机器学习》周志华 习题答案6.2
    《机器学习》周志华 习题答案4.3
    Python使用wxPython、py2exe编写桌面程序-乾颐堂
    python生成验证码,文字转换为图片-乾颐堂
    python使用wmi模块获取windows下的系统信息监控系统-乾颐堂
    Python图像处理库:Pillow 初级教程-乾颐堂
    python的metaclass浅析-乾颐堂
  • 原文地址:https://www.cnblogs.com/peteremperor/p/13995367.html
Copyright © 2020-2023  润新知