Skip to content

Commit

Permalink
added sync.Spinlock
Browse files Browse the repository at this point in the history
  • Loading branch information
OneOfOne committed Aug 26, 2014
1 parent 75d2249 commit e51b058
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
32 changes: 32 additions & 0 deletions sync/spinlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package spinlock

import (
"runtime"
"sync/atomic"
)

var state = [2]string{"Unlocked", "Locked"}

// SpinLock implements a simple atomic spin lock, the zero value for a SpinLock is an unlocked spinlock.
type SpinLock uint32

// Lock locks sl. If the lock is already in use, the calling goroutine blocks until the lock is freed.
func (sl *SpinLock) Lock() {
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
runtime.Gosched() //allow other goroutines to do stuff.
}
}

// Unlock unlocks sl, unlike [Mutex.Unlock](http://golang.org/pkg/sync/#Mutex.Unlock), there's no harm calling it on an unlocked SpinLock.
func (sl *SpinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}

// TryLock will try to lock sl and return whether it succeed or not without blocking.
func (sl *SpinLock) TryLock() bool {
return atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1)
}

func (sl *SpinLock) String() string {
return state[*sl]
}
109 changes: 109 additions & 0 deletions sync/spinlock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package spinlock

import (
"sync"
"testing"
)

type SpinMap struct {
SpinLock
m map[int]bool
}

func (sm *SpinMap) Add(i int) {
sm.Lock()
sm.m[i] = true
sm.Unlock()
}

func (sm *SpinMap) Get(i int) (b bool) {
sm.Lock()
b = sm.m[i]
sm.Unlock()
return
}

type MutexMap struct {
sync.Mutex
m map[int]bool
}

func (mm *MutexMap) Add(i int) {
mm.Lock()
mm.m[i] = true
mm.Unlock()
}

func (mm *MutexMap) Get(i int) (b bool) {
mm.Lock()
b = mm.m[i]
mm.Unlock()
return
}

type RWMutexMap struct {
sync.RWMutex
m map[int]bool
}

func (mm *RWMutexMap) Add(i int) {
mm.Lock()
mm.m[i] = true
mm.Unlock()
}

func (mm *RWMutexMap) Get(i int) (b bool) {
mm.RLock()
b = mm.m[i]
mm.RUnlock()
return
}

const N = 1e3

var (
sm = SpinMap{m: map[int]bool{}}
mm = MutexMap{m: map[int]bool{}}
rmm = RWMutexMap{m: map[int]bool{}}
)

func BenchmarkSpinL(b *testing.B) {
var wg sync.WaitGroup
for i := 0; i < b.N; i++ {
wg.Add(N * 2)
for i := 0; i < N; i++ {
go func(i int) {
sm.Add(i)
wg.Done()
}(i)
go sm.Get(i)

go func(i int) {
sm.Get(i - 1)
sm.Get(i + 1)
wg.Done()
}(i)
}
}
wg.Wait()
}

func BenchmarkMutex(b *testing.B) {
var wg sync.WaitGroup
for i := 0; i < b.N; i++ {
wg.Add(N * 2)
for i := 0; i < N; i++ {
go func(i int) {
mm.Add(i)
wg.Done()
}(i)
go mm.Get(i)
go func(i int) {
mm.Get(i - 1)
mm.Get(i + 1)
wg.Done()
}(i)
}
}
wg.Wait()
}

0 comments on commit e51b058

Please sign in to comment.