GoLang RWMutex

Sheeraz Gul Oct 11, 2022
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
Author: Sheeraz Gul
Sheeraz Gul avatar Sheeraz Gul avatar

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