Mutex Lock in Golang
Tags: go, codenewbie, beginners, tutorial
Published: 2022-03-04 15:00:14

> This article was originally posted at [ioscript.org](https://ioscript.org/mutex-locks-in-golang)

While writing concurrent code in Golang, often programs face situations when two or more goroutines try to access and modify shared variables. Such conditions can lead to inconsistency in data stored in the shared variable. Such conditions are called Race conditions. You can learn more about race conditions from our previous article of this course, [Race conditions in Golang](https://dev.to/devsaw99/race-condition-in-golang-52c1).

Let's see one example of Race Condition:

```
package main

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

var wg sync.WaitGroup

func main() {

	var counter int
	fmt.Println("Initial value: ", counter)

	// deploy 5 goroutines
	for i := 0; i < 5; i++ {

		wg.Add(1)

		go func() {
			defer wg.Done()
			//increment the counter 100 times
			for j := 0; j < 100; j++ {
				temp := counter
				time.Sleep(time.Microsecond * 1)
				temp += 1
				counter = temp
			}

		}()

	}

	wg.Wait()
	fmt.Println("Final value: ", counter)
}

```
**Output**
```
Initial value:  0
Final value:  102
```

As we can see in the output, there's definitely an inconsistency in our counter variable. The expected value of the counter is `500` and we go the `102`. Let's find out where is the issue in the above code causing the Race condition. To find the race condition in our code, we can use the command `go run -race main.go`.

When we run/build our code with the `-race` flag on. It generates the following output.

```
Initial value:  0
==================
WARNING: DATA RACE
Read at 0x00c000126008 by goroutine 8:
  main.main.func1()
      ioScript/concurrency/main.go:25 +0xa8

Previous write at 0x00c000126008 by goroutine 7:
  main.main.func1()
      ioScript/concurrency/main.go:28 +0xce

Goroutine 8 (running) created at:
  main.main()
     ioScript/concurrency/main.go:21 +0xdb

Goroutine 7 (running) created at:
  main.main()
      ioScript/concurrency/main.go:21 +0xdb
==================
Final value:  101
Found 1 data race(s)
exit status 66
``` 

We can see in the logs that go runtime found 1 data race. A race condition was found due to lines 25 and 28. There is a read operation in line 25 and a write operation at 28. Goroutine 8 is reading from the `counter` variable and Goroutine 7 is trying to write to the counter variable. 

We can solve this race condition if we somehow restrict the read and write operation of the shared variable to one goroutine at a time. 

## sync.Mutex


Mutex is a synchronization primitive which restricts one or more goroutine to enter the critical section while another goroutine is executing the critical section.

When one goroutine is executing the critical section of the code, mutex locks the section. Other goroutines need to wait till the execution is complete and the lock is released by the first goroutine.

Let's try to fix our above code using mutex lock.

```
package main

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

var wg sync.WaitGroup

func main() {

	var counter int
	var mu sync.Mutex

	fmt.Println("Initial value: ", counter)

	// deploy 5 goroutines
	for i := 0; i < 5; i++ {

		wg.Add(1)

		go func() {
			defer wg.Done()
			//increment the counter 100 times
			for j := 0; j < 100; j++ {

				mu.Lock()
				temp := counter
				time.Sleep(time.Microsecond * 1)
				temp += 1
				counter = temp
				mu.Unlock()
			}

		}()

	}

	wg.Wait()
	fmt.Println("Final value: ", counter)
}


```
**Output**

```
ioscript@ioscript:concurrency$  go run -race main.go 
Initial value:  0
Final value:  500
```

So, let's break down what we have done here. We have declared a variable name `mu` which is of type **Mutex** provided by the  **sync** package of golang. **Mutex** type provides two methods: Lock() and Unlock().

- **Lock( )**: As the name suggests, it locks the mutex. If the lock is already in use, other goroutine blocks until the mutex is available.
- **Unlock( )**: It unlocks the mutex. It throws a runtime error if the mutex is not locked when unlock was called.

In our code above, we have used `mu.Lock()` just before we are reading a value from the counter variable. Then we are incrementing the value and write the value to the counter variable again. Since read-write operations are complete, we are releasing the lock on mutex using `mu.Unlock( )` so that other goroutines can acquire the lock again and execute the critical section. 

When we run this code with the `-race` flag, we don't get any error message and the correct output is displayed in the code.

## Conclusion

In this tutorial, we had a quick look into Race conditions and how they can create data inconsistency in our program. We then learn about Mutex Locks and how we can use them to solve race conditions in our code and ensure that our program always returns expected results. 

## Before You Leave

If you found this article valuable, you can support us by dropping a like and sharing this article with your friends. You can find more articles in this series [here](https://ioscript.org/series/go-concurrency)

You can sign up for our newsletter to get notified whenever we post awesome content on Golang.

You can also **let us know what you would like to read next?** Drop a comment or email @ sonukumarsaw@ioscript.org

**Reference**

- [Go docs](https://go.dev/) 

- [Go in Action](https://g.co/kgs/ye6b6C)

- [GoByExample](https://gobyexample.com/)

- [Concurrency in Go](https://g.co/kgs/8DKFH5)



![Frame 1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645039088124/j9q9kQHgH.png)