Skip to content

Instantly share code, notes, and snippets.

@spacejam
Created September 27, 2017 19:24
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 spacejam/3ea39ab38ce10518acb4ec9c75f61a6e to your computer and use it in GitHub Desktop.
Save spacejam/3ea39ab38ce10518acb4ec9c75f61a6e to your computer and use it in GitHub Desktop.
package main
import (
"sync/atomic"
)
var (
atomicLock = int32(0)
locked = int32(1)
unlocked = int32(0)
)
// lock spins in the loop until it can "acquire" the lock
// by atomically changing the atomicLock variable from
// unlocked to locked. Our CPU will guarantee that
// only one thread/goroutine will succeed if multiple
// try to lock at the same time, and the others will
// block in the for loop until atomicLock is set to
// unlocked.
func lock() {
pointer := &atomicLock
old := unlocked
new := locked
for {
// spin until we successfully change the
// atomicLock from unlocked to locked
if atomic.CompareAndSwapInt32(pointer, old, new) {
return
}
}
}
func unlock() {
atomic.StoreInt32(&atomicLock, unlocked)
}
func main() {
lock()
defer unlock()
// do some exclusive shit
}
@empijei
Copy link

empijei commented Oct 4, 2018

I think your spinlock has some issues (as you say lock free programming helps you shooting yourself in the foot). There is a subtle issue with the runtime not being preemptive (issue here golang/go#24543 ) and a talk here https://www.youtube.com/watch?v=4CrL3Ygh7S0 so that if a Garbage Collection happens during a tight loop everything goes to sleep and you are done.

Simplest broken behavior here: https://play.golang.org/p/V2ex6SmQQMN

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment