• golang 中 sync.Mutex 和 sync.RWMutex


    介绍

    golang 中的 sync 包实现了两种锁:

    • Mutex:互斥锁
    • RWMutex:读写锁,RWMutex 基于 Mutex 实现

    Mutex(互斥锁)

    • Mutex 为互斥锁,Lock() 加锁,Unlock() 解锁
    • 在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex
    • 使用 Lock() 加锁后,不能再继续对其加锁,直到利用 Unlock() 解锁后才能再加锁
    • 在 Lock() 之前使用 Unlock() 会导致 panic 异常
    • 已经锁定的 Mutex 并不与特定的 goroutine 相关联,这样可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁
    • 在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁,会导致死锁
    • 适用于读写不确定,并且只有一个读或者写的场景

    示例

    加锁和解锁示例

    package main
    
    import (
        "time"
        "fmt"
        "sync"
    )
    
    func main() {
        var mutex sync.Mutex
        fmt.Println("Lock the lock")
        mutex.Lock()
        fmt.Println("The lock is locked")
        channels := make([]chan int, 4)
        for i := 0; i < 4; i++ {
            channels[i] = make(chan int)
            go func(i int, c chan int) {
                fmt.Println("Not lock: ", i)
                mutex.Lock()
                fmt.Println("Locked: ", i)
                time.Sleep(time.Second)
                fmt.Println("Unlock the lock: ", i)
                mutex.Unlock()
                c <- i
            }(i, channels[i])
        }
        time.Sleep(time.Second)
        fmt.Println("Unlock the lock")
        mutex.Unlock()
        time.Sleep(time.Second)
    
        for _, c := range channels {
            <-c
        }
    }
    

    程序输出:

    Lock the lock
    The lock is locked
    Not lock:  1
    Not lock:  2
    Not lock:  0
    Not lock:  3
    Unlock the lock
    Locked:  1
    Unlock the lock:  1
    Locked:  2
    Unlock the lock:  2
    Locked:  3
    Unlock the lock:  3
    Locked:  0
    Unlock the lock:  0
    

    在解锁之前加锁会导致死锁

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main(){
        var mutex sync.Mutex
        mutex.Lock()
        fmt.Println("Locked")
        mutex.Lock()
    }
    

    程序输出:

    Locked
    fatal error: all goroutines are asleep - deadlock!
    

    RWMutex(读写锁)

    • RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁
    • 读锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁
    • 写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
    • 适用于读多写少的场景

    Lock() 和 Unlock()

    • Lock() 加写锁,Unlock() 解写锁
    • 如果在加写锁之前已经有其他的读锁和写锁,则 Lock() 会阻塞直到该锁可用,为确保该锁可用,已经阻塞的 Lock() 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定
    • 在 Lock() 之前使用 Unlock() 会导致 panic 异常

    RLock() 和 RUnlock()

    • RLock() 加读锁,RUnlock() 解读锁
    • RLock() 加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加载多个
    • RUnlock() 解读锁,RUnlock() 撤销单词 RLock() 调用,对于其他同时存在的读锁则没有效果
    • 在没有读锁的情况下调用 RUnlock() 会导致 panic 错误
    • RUnlock() 的个数不得多余 RLock(),否则会导致 panic 错误

    示例

    Lock() 和 Unlock()

    package main
    
    import (
        "sync"
        "fmt"
        "time"
    )
    
    func main() {
        var mutex *sync.RWMutex
        mutex = new(sync.RWMutex)
        fmt.Println("Lock the lock")
        mutex.Lock()
        fmt.Println("The lock is locked")
    
        channels := make([]chan int, 4)
        for i := 0; i < 4; i++ {
            channels[i] = make(chan int)
            go func(i int, c chan int) {
                fmt.Println("Not lock: ", i)
                mutex.Lock()
                fmt.Println("Locked: ", i)
                fmt.Println("Unlock the lock: ", i)
                mutex.Unlock()
                c <- i
            }(i, channels[i])
        }
        time.Sleep(time.Second)
        fmt.Println("Unlock the lock")
        mutex.Unlock()
        time.Sleep(time.Second)
    
        for _, c := range channels {
            <-c
        }
    }
    

    程序输出:

    Lock the lock
    The lock is locked
    Not lock:  0
    Not lock:  1
    Not lock:  2
    Not lock:  3
    Unlock the lock
    Locked:  0
    Unlock the lock:  0
    Locked:  2
    Unlock the lock:  2
    Locked:  3
    Unlock the lock:  3
    Locked:  1
    Unlock the lock:  1
    

    Lock() 和 RLock()

    package main
    
    import (
        "sync"
        "fmt"
        "time"
    )
    
    func main() {
        var mutex *sync.RWMutex
        mutex = new(sync.RWMutex)
        fmt.Println("Lock the lock")
        mutex.Lock()
        fmt.Println("The lock is locked")
    
        channels := make([]chan int, 4)
        for i := 0; i < 4; i++ {
            channels[i] = make(chan int)
            go func(i int, c chan int) {
                fmt.Println("Not read lock: ", i)
                mutex.RLock()
                fmt.Println("Read Locked: ", i)
                fmt.Println("Unlock the read lock: ", i)
                time.Sleep(time.Second)
                mutex.RUnlock()
                c <- i
            }(i, channels[i])
        }
        time.Sleep(time.Second)
        fmt.Println("Unlock the lock")
        mutex.Unlock()
        time.Sleep(time.Second)
    
        for _, c := range channels {
            <-c
        }
    }
    

    程序输出:

    Lock the lock
    The lock is locked
    Not read lock:  2
    Not read lock:  3
    Not read lock:  1
    Not read lock:  0
    Unlock the lock
    Read Locked:  2
    Read Locked:  1
    Unlock the read lock:  2
    Unlock the read lock:  1
    Read Locked:  0
    Read Locked:  3
    Unlock the read lock:  0
    Unlock the read lock:  3
    

    Unlock() 使用之前不存在 Lock()

    package main
    
    import (
        "sync"
    )
    
    func main(){
        var rwmutex *sync.RWMutex
        rwmutex = new(sync.RWMutex)
        rwmutex.Unlock()
    }
    

    程序输出:

    panic: sync: Unlock of unlocked RWMutex
    

    RWMutex 使用不当导致的死锁

    示例1:

    package main
    
    import (
        "sync"
    )
    
    func main(){
        var rwmutex *sync.RWMutex
        rwmutex = new(sync.RWMutex)
        rwmutex.Lock()
        rwmutex.Lock()
    }
    

    程序输出:

    fatal error: all goroutines are asleep - deadlock!
    

    示例2:

    package main
    
    import (
        "sync"
    )
    
    func main(){
        var rwmutex *sync.RWMutex
        rwmutex = new(sync.RWMutex)
        rwmutex.Lock()
        rwmutex.RLock()
    }
    

    程序输出:

    fatal error: all goroutines are asleep - deadlock!
    

    RUnlock() 之前不存在 RLock()

    package main
    
    import (
        "sync"
    )
    
    func main(){
        var rwmutex *sync.RWMutex
        rwmutex = new(sync.RWMutex)
        rwmutex.RUnlock()
    }
    

    程序输出:

    panic: sync: RUnlock of unlocked RWMutex
    

    RUnlock() 个数多于 RLock()

    package main
    
    import (
        "sync"
    )
    
    func main(){
        var rwmutex *sync.RWMutex
        rwmutex = new(sync.RWMutex)
        rwmutex.RLock()
        rwmutex.RLock()
        rwmutex.RUnlock()
        rwmutex.RUnlock()
        rwmutex.RUnlock()
    }
    

    程序输出:

    panic: sync: RUnlock of unlocked RWMutex



  • 相关阅读:
    NOIP前做题记录
    AtCoder Grand Contest 021题解
    AtCoder Grand Contest 020 题解
    CODE FESTIVAL 2017 Final题解
    Code Chef October Challenge 2019题解
    5.20 校内模拟
    5.19 湖南师大附中省选模拟1
    NOI2016 循环之美
    博弈复习
    5.18 省选模拟
  • 原文地址:https://www.cnblogs.com/ExMan/p/12396766.html
Copyright © 2020-2023  润新知