-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspinlock.go
More file actions
92 lines (82 loc) · 1.96 KB
/
spinlock.go
File metadata and controls
92 lines (82 loc) · 1.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package spinlock
import (
"fmt"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
)
type SpinLock struct {
owner int64
count int
try_times int // 0 indicates that you will try to lock until you obtain.
}
func (sl *SpinLock) get() *int64 {
return &sl.owner
}
// 0 indicates that you will try to lock until you obtain.
func (sl *SpinLock) SetTryTimes(n int) bool {
sl.try_times = n
return true
}
// true - locked
// false - unlocked
func (sl *SpinLock) TryLock() bool {
me := GetGoroutineId()
if sl.owner == me {
// If the current thread has obtained the lock, increase the number of threads by one, and then return
sl.count++
return true
}
return atomic.CompareAndSwapInt64(sl.get(), 0, me)
}
func (sl *SpinLock) Lock() {
// If the lock is not obtained, spin it through CAS
if sl.try_times > 0 {
for loop := 0; loop < sl.try_times; loop++ {
if !sl.TryLock() {
runtime.Gosched()
} else {
break
}
}
} else {
for !sl.TryLock() {
runtime.Gosched()
}
}
}
func (sl *SpinLock) Unlock() {
if sl.owner != GetGoroutineId() {
panic("illegalMonitorStateError")
}
if sl.count > 0 {
// If it is greater than 0, it means that the current thread has acquired the lock multiple times,\
// and releasing the lock is simulated by subtracting count
sl.count--
} else {
// If count==0, the lock can be released, so that the number of times \
// to obtain the lock is consistent with the number of times to release the lock.
atomic.StoreInt64(sl.get(), 0)
}
}
func GetGoroutineId() int64 {
defer func() {
if err := recover(); err != nil {
fmt.Printf("panic recover:panic info:%v\n", err)
}
}()
var buf [64]byte
n := runtime.Stack(buf[:], false)
idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
id, err := strconv.ParseInt(idField, 10, 64)
if err != nil {
panic(fmt.Sprintf("cannot get goroutine id: %v", err))
}
return id
}
func NewSpinLock() sync.Locker {
var lock SpinLock
return &lock
}