Synchronisation in Golang

Mutex

package main

import (
	"fmt"
	"sync"
)

type Counter struct {
	mu    sync.Mutex
	count int
}

func (c *Counter) IncrementCount() {
	c.mu.Lock()
	c.count++
	fmt.Println(c.count)
	c.mu.Unlock()
}

func (c *Counter) GetCount() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}

func main() {
	wg := sync.WaitGroup{}
	counter := &Counter{}

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			counter.IncrementCount()
		}()
	}
	wg.Wait()
	fmt.Printf("Final count = %d\n", counter.GetCount())
}

Output

1
2
3
4
5
6
7
8
9
10
Final count = 10

Program exited.

Channel Workers Processing Tasks (Incrementing Numbers)

package main

import (
	"fmt"
	"sync"
)

/*
type Counter struct {
	mu    sync.Mutex
	count int
}

func (c *Counter) IncrementCount() {
	c.mu.Lock()
	c.count++
	fmt.Println(c.count)
	c.mu.Unlock()
}

func (c *Counter) GetCount() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}
*/

func worker(ch <-chan int, workerNumber int, wg *sync.WaitGroup) {
	defer wg.Done()
	for item := range ch {
		fmt.Printf("workerNumber=%d, item=%d\n", workerNumber, item)
	}
}

func main() {
	wg := sync.WaitGroup{}
	//counter := &Counter{}

	taskCount := 10
	workerCount := 3
	ch := make(chan int, taskCount)

	for i := 1; i <= workerCount; i++ {
		wg.Add(1)
		go worker(ch, i, &wg)
	}

	for j := 1; j < taskCount; j++ {
		ch <- j
	}

	// close needed here before waitgroup
	close(ch)

	wg.Wait()
	fmt.Println("All tasks have been processed.")

	//fmt.Printf("Final count = %d\n", counter.GetCount())
}

Output

workerNumber=3, item=1
workerNumber=3, item=4
workerNumber=3, item=5
workerNumber=3, item=6
workerNumber=3, item=7
workerNumber=3, item=8
workerNumber=3, item=9
workerNumber=1, item=2
workerNumber=2, item=3

Program exited.

Negative cases

if we do not close the channel at the end, we will seen traceback.

// close needed here
// close(ch)


workerNumber=3, item=1
workerNumber=3, item=2
workerNumber=3, item=3
workerNumber=3, item=4
workerNumber=3, item=6
workerNumber=3, item=8
workerNumber=3, item=9
workerNumber=2, item=7
workerNumber=1, item=5
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000a4f18?)
	/usr/local/go-faketime/src/runtime/sema.go:71 +0x25
sync.(*WaitGroup).Wait(0xc0000061c0?)
	/usr/local/go-faketime/src/sync/waitgroup.go:118 +0x48
main.main()
	/tmp/sandbox2297926600/prog.go:57 +0xfa

goroutine 18 [chan receive]:
main.worker(0xc0000b0000, 0x1, 0x0?)
	/tmp/sandbox2297926600/prog.go:32 +0xfc
created by main.main in goroutine 1
	/tmp/sandbox2297926600/prog.go:47 +0x58

goroutine 19 [chan receive]:
main.worker(0xc0000b0000, 0x2, 0x0?)
	/tmp/sandbox2297926600/prog.go:32 +0xfc
created by main.main in goroutine 1
	/tmp/sandbox2297926600/prog.go:47 +0x58

goroutine 20 [chan receive]:
main.worker(0xc0000b0000, 0x3, 0x0?)
	/tmp/sandbox2297926600/prog.go:32 +0xfc
created by main.main in goroutine 1
	/tmp/sandbox2297926600/prog.go:47 +0x58

Program exited.

Leave a Reply

Your email address will not be published. Required fields are marked *