Open In App

Mutex in Golang With Examples

Last Updated : 21 Apr, 2020
Improve
Improve
Like Article
Like
Save
Share
Report

A Mutex is a method used as a locking mechanism to ensure that only one Goroutine is accessing the critical section of code at any point of time. This is done to prevent race conditions from happening. Sync package contains the Mutex. Two methods defined on Mutex

  • Lock
  • Unlock

Any code present between a call to Lock and Unlock will be executed by only one Goroutine.

mutex.Lock() 

x = x + 1 // this statement be executed
          // by only one Goroutine 
          // at any point of time  

mutex.Unlock()

If one Goroutine already has the lock and if a new Goroutine is trying to get the lock, then the new Goroutine will be stopped until the mutex is unlocked. To understand this concept, let’s first understand a program having race conditions.

Program with Race Condition

Here is an example of a program which encounters race condition




// Program with race condition
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup) {  
    GFG = GFG + 1
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
  
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}


Explanation: In the program above, the worker function in line no. 12 increments the value of GFG by 1 and then calls Done() on the WaitGroup to inform its completion. The worker function is called 1000 times. Each of these Goroutines run simultaneously and race condition occurs when trying to increment GFG in line no. 13 as multiple Goroutines try to access the value of GFG concurrently. Running the same program multiple times gives different outputs each time because of the race condition.

Remember one thing, if you will check the output of the above program using the online compiler, you might get the same output every time(means no race condition) due to the deterministic nature. So use the local compiler like Visual Studio or CMD to see the results.

Solving the Above Problem Using Mutex

Here is an example of a program which how race condition is fixed.




// Program with race condition fixed by mutex
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup, m *sync.Mutex) { 
    // Lock() the mutex to ensure 
    // exclusive access to the state, 
    // increment the value,
    // Unlock() the mutex
    m.Lock() 
    GFG = GFG + 1
    m.Unlock()
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // This mutex will synchronize access to state.
    var m sync.Mutex
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w, &m)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}


Output:
Value of x 1000

Explanation: Mutex is a struct type and variable m of type Mutex is created in line no. 31. The worker function is changed so that the code which increments GFG in line no. 18 between m.Lock() and m.Unlock(). Now only one Goroutine is allowed to execute this piece of code at any point of time and thus race condition is dealt with.

The address of mutex has to be passed in line no. 37. If the mutex is passed by value instead then each Goroutine will have its own copy of the mutex and the race condition will still persist.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads