-
Notifications
You must be signed in to change notification settings - Fork 2
/
Lock.go
148 lines (125 loc) · 2.69 KB
/
Lock.go
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
采用cas实现乐观锁及TryLock
Compare And Swap 简称CAS,在sync/atomic包种
这类原子操作由名称以‘CompareAndSwap’为前缀的若干个函数代表。
声明如下
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
调用函数后,会先判断参数addr指向的被操作值与参数old的值是否相等
仅当此判断得到肯定的结果之后,才会用参数new代表的新值替换掉原先的旧值,否则操作就会被忽略。
so, 需要用for循环不断进行尝试,直到成功为止
使用锁的做法趋于悲观
我们总假设会有并发的操作要修改被操作的值,并使用锁将相关操作放入临界区中加以保护
使用CAS操作的做法趋于乐观
总是假设被操作值未曾被改变(即与旧值相等),并一旦确认这个假设的真实性就立即进行值替换。
*/
package common
import (
"runtime"
"sync/atomic"
"time"
)
const (
unlock = 0
locked = 1
)
type Lock struct {
flag int32
unlockChan chan bool
}
func NewLock() *Lock {
l := new(Lock)
l.unlockChan = make(chan bool, 3)
return l
}
func (this *Lock) Lock() {
for {
if atomic.CompareAndSwapInt32(&this.flag, unlock, locked) {
return
}
<-this.unlockChan
}
}
// 不断地尝试原子地更新flag的值,直到操作成功为止
func (this *Lock) SpinLock(count int) bool {
for i := 0; i < count; i++ {
if atomic.CompareAndSwapInt32(&this.flag, unlock, locked) {
return true
}
}
return false
}
//尝试枷锁
func (this *Lock) TryLock() bool {
return this.SpinLock(1)
}
func (this *Lock) TimeoutSpinLock(t time.Duration) bool {
tk := time.NewTicker(t)
defer tk.Stop()
for {
select {
case <-tk.C:
return this.SpinLock(1)
default:
if this.SpinLock(1024) {
return true
}
}
}
}
func (this *Lock) SchedLock() {
for {
if this.SpinLock(1024) {
return
}
runtime.Gosched()
}
}
func (this *Lock) TimeoutSchedLock(t time.Duration) bool {
tk := time.NewTicker(t)
defer tk.Stop()
for {
select {
case <-tk.C:
return this.SpinLock(1)
default:
if this.SpinLock(1024) {
return true
}
}
runtime.Gosched()
}
}
//释放锁
func (this *Lock) Unlock() {
atomic.SwapInt32(&this.flag, unlock)
select {
case this.unlockChan <- true:
default:
}
}
//分配安全的bool chan
type Semaphore struct {
flag chan bool
}
func NewSemaphore(capa int) *Semaphore {
return &Semaphore{make(chan bool, capa)}
}
func (this *Semaphore) Alloc() {
this.flag <- true
}
func (this *Semaphore) TryAlloc() bool {
select {
case this.flag <- true:
return true
default:
}
return false
}
func (this *Semaphore) Free() bool {
select {
case <-this.flag:
return true
default:
}
return false
}