Skip to content

Instantly share code, notes, and snippets.

@erikdubbelboer
Created June 5, 2022 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikdubbelboer/7c49578330566281c56cfb760fb7aca7 to your computer and use it in GitHub Desktop.
Save erikdubbelboer/7c49578330566281c56cfb760fb7aca7 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
"time"
)
type rwlock int32
func (l *rwlock) Lock() {
for {
v := atomic.AddInt32((*int32)(l), 65536)
if v>>16 == 1 {
break
}
atomic.AddInt32((*int32)(l), -65536)
runtime.Gosched()
}
for atomic.LoadInt32((*int32)(l))&(65536-1) > 0 {
runtime.Gosched()
}
}
func (l *rwlock) Unlock() {
atomic.AddInt32((*int32)(l), -65536)
}
func (l *rwlock) RLock() {
for {
if atomic.AddInt32((*int32)(l), 1)>>16 == 0 {
break
}
atomic.AddInt32((*int32)(l), -1)
for atomic.LoadInt32((*int32)(l))>>16 > 0 {
runtime.Gosched()
}
}
}
func (l *rwlock) RUnlock() {
atomic.AddInt32((*int32)(l), -1)
}
func main() {
v := int32(0)
l := rwlock(0)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 10000; i++ {
l.Lock()
// Imagine these 3 opperations do something you can't do with with a single atomic.
vv := atomic.LoadInt32(&v)
vv++
atomic.StoreInt32(&v, vv)
l.Unlock()
}
}()
}
reads := int64(0)
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
l.RLock()
v := atomic.LoadInt32(&v)
if v == 100000 {
return
}
l.RUnlock()
atomic.AddInt64(&reads, 1)
}
}()
}
go func() {
for {
fmt.Println(atomic.LoadInt32(&v))
time.Sleep(time.Millisecond * 100)
}
}()
wg.Wait()
fmt.Println(atomic.LoadInt32(&v), atomic.LoadInt64(&reads))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment