Alex

Conventional Synchronisation (Video 28)

func do() int {
  m := make(chan bool, 1)

  var n int64
  var w sync.WaitGroup

  for i := 0; i < 1000; i++ {
    w.Add(1)

    go func() {
      m <- true
      n++  // this would be a data race, however the channel here acts like a lock (a counting semaphore of count 1 is a lock)
      <-m
      w.Done()
    }()
  }

  w.Wait()
  return int(n)
}

Mutexes

type SafeMap struct {
  sync.Mutex
  m map[string]int
}

func(s *SafeMap) Incr(key string) {
  s.Lock()
  defer s.Unlock() // useful habit to defer unlock
  s.m[key]++
}

RWMutex

sync.atomic

sync.Once

var once sync.Once
var x *someSingleton

func initSingleton() {
  x = NewSingleton()
}

func handle(w http.ResponseWriter, r *http.Request) {
  once.Do(initSingleton)
  //...
}

sync.Pool

var bufPool = sync.Pool {
  New: func() any {
    return new(bytes.Buffer)
  },
}

func Log(w io.Writer, key, val string) {
  b := bufPool.Get().(*bytes.Buffer) // reflection
  b.Reset()
  // use b
  w.Write(b.Bytes())
  bufPool.Put(b) // return b to the pool
}

Homework (Video 29)