patterngoMinor
Spin-lock implementation
Viewed 0 times
implementationspinlock
Problem
I'm working on a project where a spinlock is more appropriate than a mutex, and after few tries I came up with:
It works fine, and it's even a little bit faster than
The test uses multi readers / writers to a
But I have that nagging feeling that I forgot something, so I'm wondering if my implementation is correct?
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/opThe 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?
Solution
The only weak point is that the implementation is not copy safe nor there exist mechanism for ensuring copy protection. I would hide its underlying type and return as
An alternative I've seen in
sync.Locker, so it can't be mis-used: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)
}
func SpinLock() sync.Locker {
return &spinLock{}
}An alternative I've seen in
sync.Cond is to embed an auxiliary type for copy-protection, although it would complicate the implementation unnecessary.Code Snippets
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)
}
func SpinLock() sync.Locker {
return &spinLock{}
}Context
StackExchange Code Review Q#60332, answer score: 7
Revisions (0)
No revisions yet.