Mutex
Mutual exclusion locks are a fundamental synchronization primitive used in many programming languages to protect shared resources from concurrent access.
Go also offers sync.Mutex. It can be easily implemented using a
buffered channel.
There is also RWMutex which allows multiple readers to access the
shared resource concurrently, and ensures that the writer has
exclusive access by blocking other readers and writers.
a naive counter
package main
import (
"fmt"
"sync"
)
type Conter struct {
value int64
}
func (c *Conter) Inc() {
c.value++
}
func (c *Conter) Value() int64 {
return c.value
}
func main() {
counter := &Conter{}
var wg sync.WaitGroup
inc := func() {
counter.Inc()
wg.Done()
}
for i := 0; i < 100; i++ {
wg.Add(3)
go inc()
go inc()
go inc()
}
wg.Wait()
fmt.Println(counter.Value())
}
$ go run counter.go <<<
267
using Mutex
package main
import (
"fmt"
"sync"
)
type Conter struct {
mu sync.Mutex
value int64
}
func (c *Conter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Conter) Value() int64 {
return c.value
}
func main() {
counter := &Conter{}
var wg sync.WaitGroup
inc := func() {
counter.Inc()
wg.Done()
}
for i := 0; i < 100; i++ {
wg.Add(3)
go inc()
go inc()
go inc()
}
wg.Wait()
fmt.Println(counter.Value())
}
$ go run mutex.go <<<
300
implementing Mutex using channel
package main
import (
"fmt"
"sync"
)
type Mutex chan struct{}
func NewMutex() Mutex {
return make(Mutex, 1)
}
func (m Mutex) Lock() {
m <- struct{}{}
}
func (m Mutex) Unlock() {
<-m
}
type Counter struct {
mu Mutex
value int64
}
func NewCounter() *Counter {
return &Counter{mu: NewMutex()}
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Value() int64 {
return c.value
}
func main() {
counter := NewCounter()
var wg sync.WaitGroup
inc := func() {
counter.Inc()
wg.Done()
}
for i := 0; i < 100; i++ {
wg.Add(3)
go inc()
go inc()
go inc()
}
wg.Wait()
fmt.Println(counter.Value())
}