A mutex refers to a locking mechanism that ensures only one function or goroutine is accessing a specific section of a program at a time. It is a critical part of concurrency management that prevents race conditions.

A race condition refers to an instance where more than one thread attempts to access shared data.

In this article, we will discuss the basics of implementing a mutex using the Go sync package.

Golang Sync Package

The sync package in Go provides us with tools and methods to implement synchronization tasks, such as waitgroups and mutual exclusions.

For this article, we are only interested in the mutual exclusions locks or mutex for short. The sync package provides us with two methods to implement mutex in the Go programs:

  1. Lock()
  2. Unlock()

If you place any code between the lock and unlock methods, Go programs will only allow a single thread or goroutine to access that code.

Let us take a simple program with race conditions:

package main


import (


    “fmt”


    “sync”

)


var x = 1

func add(wg *sync.WaitGroup) {


    x


    wg.Done()

}


func main() {


    var waitgroup sync.WaitGroup


    for i := 0; i < 10000; i {


        waitgroup.Add(1)


        go add(&waitgroup)


    }


    waitgroup.Wait()


    fmt.Println(x)

}

In the previous example, we have a function that takes the value of x and increments it by 1. The function then tells the waitgroup to unblock the wait mechanism using the Done() function.

Inside the main function, we run at least 10,000 goroutines concurrently, each trying to access and change the value of x.

Since there is no deterministic order to run the goroutines, the (increment the value of x) value of x changes at every run.

To solve for the previous race condition, we can use a mutex as shown below:

 package main


import (


    “fmt”


    “sync”

)


var x = 1

func add(wg *sync.WaitGroup, mx *sync.Mutex) {


    // lock access to this value


    mx.Lock()


    x


    mx.Unlock()


    wg.Done()

}


func main() {


    var waitgroup sync.WaitGroup


    var mutex sync.Mutex


    for i := 0; i < 10000; i {


        waitgroup.Add(1)


        go add(&waitgroup, &mutex)


    }


    waitgroup.Wait()


    fmt.Println(x)

}

Here, we add mx of type sync.Mutex to the add function. Then, we lock the increment operator to allow a single goroutine at a time.

Closing

This article covered the fundamentals of implementing a mutex in Go using the sync package to fix a simple race condition. We hope you found this article helpful. Check out other Linux Hint Articles for more tips and information.

About the author

<img data-del="avatar" data-lazy-src="https://kirelos.com/wp-content/uploads/2022/02/echo/john-150×150.png6215f614418de.jpg" height="112" src="data:image/svg xml,” width=”112″>

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list