Home

Published

- 2 min read

sync.Mutex

img of sync.Mutex

Background

mu.RLock() Concurrency helps us complete tasks faster, however, sometimes concurrency breaks things. Mutex is a way for us to eliminate concurrency when we don’t want it.

ELI5 Why we need it

Imagine sitting in the classroom and the teacher is asking for the birthdays of everyone. If everyone shouted their birthday at the same time, the teacher would get confused and things go havoc.

In this case, if each student raise their hand and gets permission from the teacher first, things would be smoother.

How to use it

First, let us define a function to mimic a teacher recording their birthday:

// recordBirthday mimics the teacher recording a student's birthday
func recordBirthday(birthday int) {
	// for simplicity, records here is a global variable, []int
	records = append(records, birthday)
}

Now, we can test what happens if a class with 32 students shouts at the same time.

func recordClassBirthday() {
	for i := 0 ; i<32 ; i++ {
		go func (birthday int)  {
			recordBirthday(birthday)
		}(i)
	}
	time.Sleep(200*time.Microsecond) // wait for everyone to shout
	fmt.Println(len(records))
}
// Output: 17

Oh no, the teacher only managed to record 17 students’ birthdays…

Now see what happens when we remove concurrency via a mutex

func recordClassBirthdayWithMutex() {
	mu := sync.Mutex{}
	for i := 0 ; i<32 ; i++ {
		go func (birthday int)  {
			mu.Lock()
			recordBirthday(birthday)
			mu.Unlock()
		}(i)
	}
	time.Sleep(200*time.Microsecond)

	fmt.Println(len(records))
}
// Output: 32

With concurrency eliminated with a mutex, the teacher could record all 32 students’ birthdays correctly.

Let’s list the key components here:

  1. mu.Lock()
  2. mu.Unlock()

mu.Lock()

This function ensures that only the goroutine that has obtained the lock gets to execute its code, and the rest is blocked until that goroutine releases the lock.

mu.Unlock()

A function to release the lock to give other goroutines a chance to obtain.

Rabbit hole

sync.Mutex also provides mu.RLock() in cases where concurrent reads are allowed but concurrent writes are not. This is useful if you want to increase the overall QPS on heavy read and little write scenarios.

Alright, that is all for today. Let’s get one post smarter every day, and see you tomorrow! mu.RUnlock

https://pkg.go.dev/sync#Mutex.Lock

Subscribe

* indicates required

Intuit Mailchimp