Created
January 17, 2016 23:14
-
-
Save mem/8b67297e706aff3e16d0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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