Reputation: 1473
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
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?
2) What happens when someone already acquired Lock() for map ,will other go-routine can still get RLock()
3) Assuming we are dealing with Maps here, is there any possibility of "concurrent read/write of Map" error can come?
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
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