Golang 中的 RLock() 和 Lock() 有什么区别?

Sha*_* BJ 14 mutex go

Golang 中的 RLock() 和 Lock() 之间有什么区别,以及当我们使用互斥锁时如何有效地使用它们?

nig*_*204 28

Lock():通过获取锁,一次只有一个 goroutine 读/写。

RLock():多个goroutine可以通过获取锁一次读取(不写入)。

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {

    a := 0

    lock := sync.RWMutex{}

    for i := 1; i < 10; i++ {
        go func(i int) {
            lock.Lock()
            fmt.Printf("Lock: from go routine %d: a = %d\n",i, a)
            time.Sleep(time.Second)
            lock.Unlock()
        }(i)
    }

    b := 0

    for i := 11; i < 20; i++ {
        go func(i int) {
            lock.RLock()
            fmt.Printf("RLock: from go routine %d: b = %d\n",i, b)
            time.Sleep(time.Second)
            lock.RUnlock()
        }(i)
    }

    <-time.After(time.Second*10)
}
Run Code Online (Sandbox Code Playgroud)

1) 当一个 go-routine 已经获得了一个 RLock() 时,另一个 go-routine 是否可以获取一个 Lock() 进行写入,或者它必须等到 RUnlock() 发生?

  • 要获取 Lock() 进行写入,它必须等到 RUnlock()

2) 当有人已经为 map 获取了 Lock() 时会发生什么,其他 go-routine 是否仍然可以获取 RLock()

  • 如果某人 X 已经获得了 Lock(),那么其他 go-routine 来获得 RLock() 将不得不等到 X 释放锁 (Unlock())

3) 假设我们在这里处理 Maps,是否有可能出现“并发读/写 Map”错误?

  • Map 不是线程安全的。所以“并发读/写 Map”会导致错误。

有关更多说明,请参见以下示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    lock := sync.RWMutex{}

    b := map[string]int{}
    b["0"] = 0

    go func(i int) {
        lock.RLock()
        fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["0"])
        time.Sleep(time.Second*3)
        fmt.Printf("RLock: from go routine %d: lock released\n",i)
        lock.RUnlock()
    }(1)

    go func(i int) {
        lock.Lock()
        b["2"] = i
        fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["2"])
        time.Sleep(time.Second*3)
        fmt.Printf("Lock: from go routine %d: lock released\n",i)
        lock.Unlock()
    }(2)

    <-time.After(time.Second*8)

    fmt.Println("*************************************8")

    go func(i int) {
        lock.Lock()
        b["3"] = i
        fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["3"])
        time.Sleep(time.Second*3)
        fmt.Printf("Lock: from go routine %d: lock released\n",i)
        lock.Unlock()
    }(3)

    go func(i int) {
        lock.RLock()
        fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["3"])
        time.Sleep(time.Second*3)
        fmt.Printf("RLock: from go routine %d: lock released\n",i)
        lock.RUnlock()
    }(4)

    <-time.After(time.Second*8)
}
Run Code Online (Sandbox Code Playgroud)