Mutex in Golang With Examples

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

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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)
}

chevron_right


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.

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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)
}

chevron_right


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.




My Personal Notes arrow_drop_up


If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :

Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.