A mutex is named after the concept of mutual exclusion. Which is what they do as well. They lock a block of code till execution is complete for another go routine to access it.
Example from Go In Action:
package main
import (
"fmt"
"runtime"
"sync"
)
var (
// counter will be incremented by all go routines
counter int
wg sync.WaitGroup
mutex sync.Mutex
)
func main() {
wg.Add(2)
go incCounter(1)
go incCounter(2)
wg.Wait()
fmt.Println("Final Counter:", counter)
}
func incCounter(id int) {
defer wg.Done()
for count := 0; count < 2; count++ {
// will only allow one go routine through this critical section at a
// time
mutex.Lock()
value := counter
// even when thread is yielded, mutex retains execution with the same
// go routine
runtime.Gosched()
value++
counter = value
// release the lock
mutex.Unlock()
}
}
Although this works, it does not make writing concurrent programs easier or less error prone or fun. So for this reason channels are a much better alternative. Which I will cover in another gist. :)