Hello!

Today we will learn what is RWMutex and how to use it. RWMutex is a read/write exclusion lock. A lock can have any number of readers or one writer.

RWMutex has the following methods:

func (rw *RWMutex) Lock() // Write Lock
func (rw *RWMutex) RLock() // Read Lock
func (rw *RWMutex) RUnlock() // Read Unlock
func (rw *RWMutex) Unlock() // Write Unlock

Now let’s see how it can be used. In the first example, let’s try read lock

package main

import (
    "sync"
    "time"
    "fmt"
)

var (
	m = sync.RWMutex{}
)

func main() {
    go read(1)
    go read(2)
    time.Sleep(2 * time.Second)
}

func read(i int) {
    fmt.Println("Acquiring lock", i)
    m.RLock()
    fmt.Println("Reading", i)
    time.Sleep(1 * time.Second)
    m.RUnlock()
    fmt.Println("Released lock", i)
}

When the script is executed, in the results output, we can see that several go routines were able to perform a read operation at the same time.

Acquiring lock 1
Reading 1
Acquiring lock 2
Reading 2
Released lock 1
Released lock 2

Now let’s see how Write Lock works

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
	m = sync.RWMutex{}
)

func main() {
    go write(1)
    go read(2)
    go write(3)
    time.Sleep(5 * time.Second)
}

func read(i int) {
    fmt.Println("Acquiring read lock", i)
    m.RLock()
    fmt.Println("Reading", i)
    time.Sleep(1 * time.Second)
    m.RUnlock()
    fmt.Println("Released read lock", i)
}

func write(i int) {
    fmt.Println("Acquiring write lock", i)
    m.Lock()
    fmt.Println("Writing", i)
    time.Sleep(1 * time.Second)
    m.Unlock()
    fmt.Println("Released write lock", i)
}

From script output, we can see that at first Write Lock was acquired, write operation completed, and lock released. Then Read Lock acquired, reading operation completed, lock released. And finally last write operation completed.

Acquiring write lock 3
Writing 3
Acquiring write lock 1
Acquiring read lock 2
Reading 2
Released write lock 3
Released read lock 2
Writing 1
Released write lock 1