skip to content
Alvin Lucillo

Mutex demo in Go

/ 2 min read

💻 Tech

Yesterday, I wrote about mutex, and how it can help maintain concurrency safety in Go. Now, I will show you a simple demo:

// main.go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(10)

	repo := &Repo{}

	go func() {
		for i := 1; i <= 10; i++ {
			go func(i int) {
				defer wg.Done()
				repo.Add("id", fmt.Sprintf("%d", i), i)
				fmt.Printf("%d - current repo value: %v\n", i, repo.values)
			}(i)
		}

	}()

	wg.Wait()
}
// repo.go
package main

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

type Repo struct {
	values map[string]string
	mutex  sync.Mutex
}

func (r *Repo) Add(id string, val string, sleepSec int) {
	defer r.mutex.Unlock()
	r.mutex.Lock()

	fmt.Printf("%d - waiting for %d seconds\n", sleepSec, 10-sleepSec)
	time.Sleep(time.Duration(10-sleepSec) * time.Second)

	if r.values == nil {
		r.values = make(map[string]string)
	}
	r.values[id] = val
}
# Output:
 go run .
10 - waiting for 0 seconds
5 - waiting for 5 seconds
10 - current repo value: map[id:10]
5 - current repo value: map[id:5]
1 - waiting for 9 seconds
1 - current repo value: map[id:1]
2 - waiting for 8 seconds
2 - current repo value: map[id:2]
7 - waiting for 3 seconds
7 - current repo value: map[id:7]
6 - waiting for 4 seconds
6 - current repo value: map[id:6]
8 - waiting for 2 seconds
8 - current repo value: map[id:8]
9 - waiting for 1 seconds
9 - current repo value: map[id:9]
3 - waiting for 7 seconds
3 - current repo value: map[id:3]
4 - waiting for 6 seconds
4 - current repo value: map[id:4]

Explanation:

  • The main function creates 10 goroutines with each goroutine calls the repo’s Add method
  • The Add method locks the mutex and waits for 10-i seconds (i.e., if current iteration is 1, then it blocks the execution for 9 seconds)
  • The sleep simulates a process that takes some time to complete but requires a lock on the resource
  • In the output, each goroutine doesn’t complete until the lock is released