Skip to content

Instantly share code, notes, and snippets.

@mem
Created January 17, 2016 23:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mem/8b67297e706aff3e16d0 to your computer and use it in GitHub Desktop.
Save mem/8b67297e706aff3e16d0 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"sync"
"time"
)
type RWMutex struct {
qr chan struct{} // queue of readers
qw chan struct{} // queue of writers
ra chan struct{} // reader acquire channel
rr chan struct{} // reader release channel
wa chan struct{} // writer acquire channel
wr chan struct{} // writer release channel
}
func NewRWMutex() *RWMutex {
m := &RWMutex{
qr: make(chan struct{}),
qw: make(chan struct{}),
ra: make(chan struct{}),
rr: make(chan struct{}),
wa: make(chan struct{}),
wr: make(chan struct{}),
}
go func() {
n := 0
nw := 0
for {
switch {
case n < 0:
// a writer has the lock
<-m.wr
n++
case nw > 0:
// there might be readers holding the lock
for n > 0 {
<-m.rr
n--
}
// there's a writer waiting
m.wa <- struct{}{}
n--
nw--
default:
// no writers are waiting
select {
case <-m.qw:
nw++
case <-m.qr:
m.ra <- struct{}{}
n++
case <-m.rr:
n--
}
}
}
}()
return m
}
func (m *RWMutex) Lock() {
m.qw <- struct{}{}
<-m.wa
}
func (m *RWMutex) Unlock() {
m.wr <- struct{}{}
}
func (m *RWMutex) RLock() {
m.qr <- struct{}{}
<-m.ra
}
func (m *RWMutex) RUnlock() {
m.rr <- struct{}{}
}
type Tracker struct {
m sync.Mutex
Data []int
}
func (t *Tracker) Track(i int) {
t.m.Lock()
t.Data = append(t.Data, i)
t.m.Unlock()
}
func main() {
wg := &sync.WaitGroup{}
m := NewRWMutex()
t := Tracker{Data: []int{}}
N := 4
M := 5
for i := 0; i < 4*N; i++ {
wg.Add(1)
go func(i int) {
time.Sleep(50 * time.Millisecond)
for j := 0; j < M; j++ {
m.Lock()
t.Track(1000 + i)
m.Unlock()
time.Sleep(50 * time.Millisecond)
}
wg.Done()
}(i)
}
for i := 0; i < N; i++ {
wg.Add(1)
go func(i int) {
for j := 0; j < M; j++ {
m.RLock()
t.Track(i)
m.RUnlock()
time.Sleep(25 * time.Millisecond)
}
wg.Done()
}(i)
}
wg.Wait()
for _, t := range t.Data {
fmt.Println(t)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment