I'm working on a project where a spinlock is more appropriate than a mutex, and after few tries I came up with:
type SpinLock uint32
func (sl *SpinLock) Lock() {
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
runtime.Gosched() //without this it locks up on GOMAXPROCS > 1
}
}
func (sl *SpinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}
It works fine, and it's even a little bit faster than sync.Mutex
, and 2x the speed of sync.RWMutex
.
➜ go test -bench=. -benchmem -v -cpu 4
BenchmarkSpinL-4 2000 1078798 ns/op 33923 B/op 2006 allocs/op
BenchmarkMutex-4 2000 1195814 ns/op 32781 B/op 2002 allocs/o
BenchmarkRWMutex-4 1000 2352117 ns/op 78253 B/op 2147 allocs/op
The test uses multi readers / writers to a map[int]*struct{int, int}
. Running it with -race
doesn't detect any data races, either.
But I have that nagging feeling that I forgot something, so I'm wondering if my implementation is correct?