Golang lock/mutex

A lock, or mutex, is a synchronization technique and important concurrent programming concept.
Suppose you are writing a Go program where there is more than one thread or goroutine executing concurrently. These goroutines share a variable among them – so you’ll want to ensure that only one goroutine accesses the variable at a time to avoid conflicts. This is where mutexes come in.

Mutex provides mutual exclusion to a resource, which means that only one goroutine can hold it at a time. Any goroutine must first acquire the mutex and then access the resource. If a goroutine tries to acquire the mutex already held by another goroutine, it will be blocked and will wait for the mutex to be released.

Alright, that’s enough talk about what mutexes are and how they work. Let’s see how they are implemented in Go.
Go’s standard library provides mutual exclusion with sync.Mutex and its two methods: Lock and Unlock.

Syntax

  • m.Lock(): Locks the mutex, m. If the lock is already in use, call goroutine blocks until the mutex is available.
  • m.Unlock(): Unlocks the mutex, m. A run-time error is thrown if m is not already locked.

Example

In this example, we declare the variable balance, which will be our shared resource. We then define the counter()function, which accesses and increments balance using a loop.
We execute counter() in two goroutines. Since both goroutines will access balance at the same time, there will be conflicts. Hence, we wrap the loop inside the m.Lock() and m.Unlock so that only one goroutine can access balance at one time. time.Sleep() is just there so goroutines can finish before printing balance.

Try commenting out the mutex code – you will notice that balance is printed incorrectly.

package main
import (
"fmt"
"sync"
"time"
)
func main() {
// Balance: shared variable
balance := 0
// A single mutex to be used by both goroutines
var m sync.Mutex
// Function that accesses balance multiple times
counter := func() {
m.Lock()
for i := 0; i < 10000000; i++ {
balance = balance + 10
}
m.Unlock()
}
// Starting two goroutines
go counter()
go counter()
// Waiting and then printing balance
time.Sleep(time.Second)
fmt.Printf("Balance: %v", balance) // should be 200000000
}
Copyright ©2024 Educative, Inc. All rights reserved