Sharath BJ
Sharath BJ

Reputation: 1473

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

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

Upvotes: 32

Views: 31170

Answers (2)

nightfury1204
nightfury1204

Reputation: 4654

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

Upvotes: 58

L.Hao
L.Hao

Reputation: 37

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.

Upvotes: 3

Related Questions