-
-
Save ericmoritz/992ddd2d96901728e3f315114fc5926d to your computer and use it in GitHub Desktop.
WithLock pattern with a RWLock
This file contains 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
Unsafe: | |
unsafe: Dirty read! (0 != 1 at 0) | |
unsafe: Dirty read! (0 != 2 at 0) | |
unsafe: Dirty read! (0 != 3 at 0) | |
unsafe: Dirty read! (0 != 4 at 0) | |
unsafe: Dirty read! (0 != 5 at 0) | |
unsafe: Dirty read! (0 != 6 at 0) | |
unsafe: Dirty read! (0 != 7 at 0) | |
unsafe: Dirty read! (0 != 8 at 0) | |
Safe?: |
This file contains 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" | |
"math/rand" | |
"sync" | |
"time" | |
) | |
type Locker struct { | |
inner *Inner | |
lock *sync.RWMutex | |
} | |
type Inner struct { | |
Data []int | |
} | |
func (self *Locker) WithRead(fn func(x *Inner)) { | |
self.lock.RLock() | |
defer self.lock.RUnlock() | |
fn(self.inner) | |
} | |
func (self *Locker) WithWrite(fn func(x *Inner)) { | |
self.lock.Lock() | |
defer self.lock.Unlock() | |
fn(self.inner) | |
} | |
func dirty_read_detector(kind string, inner *Inner) { | |
last := inner.Data[0] | |
for i, x := range inner.Data[1:] { | |
if x != last { | |
fmt.Printf("%v: Dirty read! (%v != %v at %v)\n", kind, x, last, i) | |
break | |
} | |
} | |
} | |
func randomSleep() { | |
time.Sleep(time.Duration(rand.Int31n(100)) * time.Millisecond) | |
} | |
func write_all(n int, inner *Inner) { | |
for i, _ := range inner.Data { | |
inner.Data[i] = n | |
randomSleep() | |
} | |
} | |
func unsafe_writer(n int, wg *sync.WaitGroup) { | |
write_all(n, unsafeInner) | |
wg.Done() | |
} | |
func unsafe_reader(wg *sync.WaitGroup) { | |
dirty_read_detector("unsafe", unsafeInner) | |
wg.Done() | |
} | |
func safe_writer(n int, wg *sync.WaitGroup) { | |
locker.WithWrite(func(x *Inner) { | |
write_all(n, x) | |
}) | |
wg.Done() | |
} | |
func safe_reader(wg *sync.WaitGroup) { | |
locker.WithRead(func(x *Inner) { | |
dirty_read_detector("safe", x) | |
}) | |
wg.Done() | |
} | |
var locker *Locker | |
var unsafeInner *Inner | |
func init() { | |
locker = &Locker{ | |
inner: &Inner{Data: make([]int, 100)}, | |
lock: &sync.RWMutex{}, | |
} | |
unsafeInner = &Inner{Data: make([]int, 100)} | |
} | |
func main() { | |
fmt.Println("Unsafe:") | |
var wg sync.WaitGroup | |
for i := 0; i < 10; i++ { | |
wg.Add(1) | |
go unsafe_writer(i, &wg) | |
wg.Add(1) | |
go unsafe_reader(&wg) | |
} | |
wg.Wait() | |
fmt.Println("Safe?:") | |
fmt.Println("Safe:") | |
for i := 0; i < 10; i++ { | |
wg.Add(1) | |
go safe_writer(i, &wg) | |
wg.Add(1) | |
go safe_reader(&wg) | |
} | |
wg.Wait() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment