DEV Community

Cover image for What is a Mutex in Golang?
Kevin Naidoo
Kevin Naidoo

Posted on • Updated on • Originally published at kevincoder.co.za

What is a Mutex in Golang?

When you build Golang programs, you will almost always find a use for Goroutines.

Goroutines are powerful and generally easy to use, however, if you need to modify some piece of data that is shared between Goroutines - then you may run into some trouble with data integrity.

In this article, we will look at what is a "Mutex" and how to use it.

What is a Mutex?

In Golang; a Goroutine is essentially a function that is put in a background queue and executed concurrently whenever resources are available.

package main

import (
    "fmt"
    "sync"
)

var NUM_PROCESSED = 0

func countNumProcessed(wg *sync.WaitGroup) {
    defer wg.Done()
    NUM_PROCESSED++
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 500; i++ {
        wg.Add(1)
        go countNumProcessed(&wg)
    }

    wg.Wait()
    fmt.Println(NUM_PROCESSED)
}
Enter fullscreen mode Exit fullscreen mode

If we remove the "go" keyword, each function call to "countNumProcessed" will block the loop and wait for this function to finish before continuing with the loop.

When you use the "go" keyword, these functions will be run concurrently. Which then makes it possible for 2 or more functions to modify the variable at the same time.

If you run this code a few times - you will notice that the total count fluctuates.

This is because each Goroutine, for a few nanoseconds copies the value of "NUM_PROCESSED" in memory to increment it and then update the variable.

If two (or more) Goroutines copy the value around the same time, they will not be aware of updates made by other Goroutines.

For example: let's assume the value was "200"; each of the two Goroutines will add "1" i.e. "201". Thus the value for "NUM_PROCESSED" will become "201" instead of "202".

This is where a Mutex comes in handy. A Mutex will create a "lock" in the process - so that only one Goroutine can update "NUM_PROCESSED" at a time.

Goroutines

The other Goroutines will then be paused until the lock is released. This is very similar to a queue - when each Goroutine releases the lock, the next one acquires a new lock and the process continues until all the queued Goroutines finish updating "NUM_PROCESSED".

A Mutex example

We can modify the above code to introduce a Mutex as follows:

package main

import (
    "fmt"
    "sync"
)

var NUM_PROCESSED = 0
var MUTEX sync.Mutex

func countNumProcessed(wg *sync.WaitGroup) {
    defer wg.Done()
    MUTEX.Lock()
    NUM_PROCESSED++
    MUTEX.Unlock()
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 500; i++ {
        wg.Add(1)
        go countNumProcessed(&wg)
    }

    wg.Wait()
    fmt.Println(NUM_PROCESSED)
}
Enter fullscreen mode Exit fullscreen mode

You will notice with the above code, that no matter how many times you run this function, it will always print "500". This is precisely the same amount of goroutines created in the for loop.

Top comments (4)

Collapse
 
livioribeiro profile image
Livio Ribeiro

Does Go have atomic types, e.g AtomicInt?

Collapse
 
kwnaidoo profile image
Kevin Naidoo • Edited

Thanks - this is a good question. I used a basic counter to explain a mutex in the simplest possible way, however, atomic types are usually a better fit for primitive types like ints.

The go standard library provides a package for atomic types: "sync/atomic". Channels also is an option as well.

Collapse
 
xvbnm48 profile image
M Fariz Wisnu prananda

thanks for sharing!

Collapse
 
georgexp97 profile image
Georgexp97

This is a very interesting issue.