zoukankan      html  css  js  c++  java
  • 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 输出就一定是没发生。

  • 相关阅读:
    Python Revisited Day 13 (正则表达式)
    Python Revisited Day 06 (面向对象程序设计)
    Python Revisited (变量)
    Python Revisited Day 05(模块)
    Python Revisited Day 04 (控制结构与函数)
    Python Revisited Day 03 (组合数据类型)
    Numpy
    Python Revisited Day 01
    Python3使用openpyxl读写Excel文件
    Python3操作YAML文件
  • 原文地址:https://www.cnblogs.com/peteremperor/p/13995367.html
Copyright © 2011-2022 走看看