what is the difference between RLock() and Lock() in Golang?

13,339

Solution 1

Lock(): only one go routine read/write at a time by acquiring the lock.

RLock(): multiple go routine can read(not write) at a time by acquiring the lock.

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)
}

1) When a go-routine has already acquired a RLock(), can another go-routine acquire a Lock() for write or it has to wait until RUnlock() happens?

  • To acquire a Lock() for write it has to wait until RUnlock()

2) What happens when someone already acquired Lock() for map ,will other go-routine can still get RLock()

  • if someone X already acquired Lock(), then other go-routine to get RLock() will have to wait until X release lock (Unlock())

3) Assuming we are dealing with Maps here, is there any possibility of "concurrent read/write of Map" error can come?

  • Map is not thread safe. so "concurrent read/write of Map" can cause error.

See following example for more clarification:

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)
}

Solution 2

A RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer. The zero value for a RWMutex is an unlocked mutex.

A RWMutex must not be copied after first use.

If a goroutine holds a RWMutex for reading and another goroutine might call Lock, no goroutine should expect to be able to acquire a read lock until the initial read lock is released. In particular, this prohibits recursive read locking. This is to ensure that the lock eventually becomes available; a blocked Lock call excludes new readers from acquiring the lock.


A Mutex is a mutual exclusion lock. The zero value for a Mutex is an unlocked mutex.

The golang provide the channel is the best practice for concurrency control, so i think the efficiently way using sync.lock is not used it, use channel instead.

Share:
13,339
Sharath BJ
Author by

Sharath BJ

Updated on July 16, 2022

Comments

  • Sharath BJ
    Sharath BJ almost 2 years

    what is the difference between RLock() and Lock() in Golang and how they can be used efficiently when we use mutex Lock ?