GoLang RWMutex
This tutorial demonstrates how to use rwmutex
in GoLang.
GoLang RWMutex
A mutex
is short for mutual exclusion that is used to track which thread has accessed a variable at any time. The mutexes are the data structure provided in the sync
package of GoLang.
The mutexes
are used when performing concurrency using the Go code. Here is a simple example of using mutex
in GoLang.
package main
import (
"fmt"
"sync"
"time"
)
func EvenNumber(num int) bool {
return num%2 == 0
}
func main() {
num := 2
var DemoMutex sync.Mutex
go func() {
DemoMutex.Lock()
defer DemoMutex.Unlock()
EvenNum := EvenNumber(num)
time.Sleep(5 * time.Millisecond)
if EvenNum {
fmt.Println("The number", num, " is even")
return
}
fmt.Println("The number", num, "is odd")
}()
go func() {
DemoMutex.Lock()
num++
DemoMutex.Unlock()
}()
time.Sleep(time.Second)
}
The code above checks for the number if it is even or odd. Here concurrent goroutines
can corrupt the data, so we use a mutex
to lock and unlock data to prevent it from corruption.
See the output:
The number 2 is even
The mutex
and RWmutex
are different where the mutex
is a simple mutex, and RWmutex
is a reader-writer mutual exclusion lock. With the RWMutex
, the lock is held by an arbitrary number of readers or one writer.
When the value for RWMutex
is zero, it is an unlocked mutex. Let’s try the same example with the RWMutex
mutex.
package main
import (
"fmt"
"sync"
"time"
)
func EvenNumber(num int) bool {
return num%2 == 0
}
func main() {
num := 2
var DemoRWM sync.RWMutex
// both goroutines call DemoRWM.Lock() before accessing `num` and then call the DemoRWM.Unlock after they are done
go func() {
DemoRWM.RLock()
defer DemoRWM.RUnlock()
EvenNum := EvenNumber(num)
time.Sleep(5 * time.Millisecond)
if EvenNum {
fmt.Println("The number", num, " is even")
return
}
fmt.Println("The number", num, "is odd")
}()
go func() {
DemoRWM.Lock()
num++
DemoRWM.Unlock()
}()
time.Sleep(time.Second)
}
As we can see here, both goroutines
call DemoRWM.Lock()
before accessing num
and then call the DemoRWM.Unlock
after they are done. The code uses RWMutex
.
See the output:
The number 2 is even
Let’s try another example for RWMutex
where the RWMutex
allows all the readers to access the data simultaneously, and the writer will lock out the others.
See the example:
package main
import (
"fmt"
"sync"
)
func main() {
DemoMap := map[int]int{}
DemoRWM := &sync.RWMutex{}
go LoopWrite(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
go LoopRead(DemoMap, DemoRWM)
// stop the program from exiting must be killed
StopBlock := make(chan struct{})
<-StopBlock
}
func LoopRead(DemoMap map[int]int, DemoRWM *sync.RWMutex) {
for {
DemoRWM.RLock()
for k, v := range DemoMap {
fmt.Println(k, "-", v)
}
DemoRWM.RUnlock()
}
}
func LoopWrite(DemoMap map[int]int, DemoRWM *sync.RWMutex) {
for {
for i := 0; i < 100; i++ {
DemoRWM.Lock()
DemoMap[i] = i
DemoRWM.Unlock()
}
}
}
As we can see, the RWMutex
allows us to use the read
as many times as we want; the output for this code will be something like this:
timeout running program
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
1 - 1
Sheeraz is a Doctorate fellow in Computer Science at Northwestern Polytechnical University, Xian, China. He has 7 years of Software Development experience in AI, Web, Database, and Desktop technologies. He writes tutorials in Java, PHP, Python, GoLang, R, etc., to help beginners learn the field of Computer Science.
LinkedIn Facebook