Table of Contents
- Introduction
- Prerequisites
- Overview
- Step 1: Understanding Mutex
- Step 2: Creating a Safe Counter
- Step 3: Testing the Safe Counter
- Recap
Introduction
In concurrent programming, when multiple goroutines access the same data simultaneously, it can lead to race conditions and unpredictable behavior. The Go language provides the sync.Mutex
type to synchronize access to shared resources and ensure safe data access. In this tutorial, you will learn how to use sync.Mutex
to protect shared data and prevent race conditions in Go.
By the end of this tutorial, you will have a clear understanding of how to use sync.Mutex
to safely access shared data, preventing race conditions and ensuring consistent results in your Go programs.
Prerequisites
To follow along with this tutorial, you should have basic knowledge of the Go programming language and be familiar with goroutines and concurrency concepts. You should have Go installed on your machine. If you haven’t installed Go, you can download and install it from the official website: https://golang.org/dl/.
Overview
- Understand Mutex
-
Create a safe counter using Mutex
- Test the safe counter
Step 1: Understanding Mutex
A Mutex
is a synchronization primitive that allows exclusive access to a resource. It provides two methods: Lock
and Unlock
. When a goroutine calls Lock
, it acquires the exclusive access to the resource, allowing it to perform operations on the shared data. Other goroutines that try to acquire the lock while it is held by another goroutine will be blocked until the lock is released.
The Unlock
method is used to release the lock, allowing other goroutines to acquire it. It is crucial to ensure that every Lock
call is eventually followed by an Unlock
call to prevent deadlocks where a lock is never released.
Step 2: Creating a Safe Counter
Let’s create an example where multiple goroutines increment a counter concurrently. Without synchronization, race conditions can occur, leading to incorrect results. We will use sync.Mutex
to protect the counter and ensure safe access.
package main
import (
"fmt"
"sync"
)
type SafeCounter struct {
counter int
mutex sync.Mutex
}
func (sc *SafeCounter) Increment() {
sc.mutex.Lock()
defer sc.mutex.Unlock()
sc.counter++
}
func (sc *SafeCounter) Value() int {
sc.mutex.Lock()
defer sc.mutex.Unlock()
return sc.counter
}
func main() {
var wg sync.WaitGroup
counter := SafeCounter{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
counter.Increment()
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter value:", counter.Value())
}
In the code above, we define a SafeCounter
struct that includes an int
field for the counter value and a sync.Mutex
field for synchronization. The Increment
method locks the mutex, increments the counter, and then unlocks the mutex. The Value
method also acquires and releases the mutex, returning the current counter value.
Inside the main
function, we create a SafeCounter
instance and launch 100 goroutines. Each goroutine calls the Increment
method on the counter and then signals its completion using the WaitGroup
wg.Done()
method. Finally, after waiting for all goroutines to finish, we print the counter value.
Step 3: Testing the Safe Counter
Build and run the program using the following command:
go run main.go
You should see the output:
Counter value: 100
Even though multiple goroutines increment the counter concurrently, the sync.Mutex
ensures that they access it safely, preventing any race conditions and producing the correct result.
Recap
In this tutorial, you have learned how to use sync.Mutex
to ensure safe data access in Go programs. By using a mutex, you can synchronize access to shared resources and prevent race conditions. Remember to acquire the lock using Lock
before accessing the shared data and release the lock using Unlock
when done.
Following these practices will help you write concurrent Go programs that exhibit predictable behavior and avoid race conditions.
During the tutorial, we covered the following topics:
- Understanding the purpose of a
sync.Mutex
- Creating a safe counter by implementing the
Increment
andValue
methods - Testing the safe counter with multiple goroutines
- Building and running the program
Now that you have a good understanding of sync.Mutex
, you can confidently apply it to protect shared data in your own Go programs.
The complete code for this tutorial can be found on GitHub.