-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsemaphore.go
98 lines (74 loc) · 1.39 KB
/
semaphore.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
package batch
import "sync"
type (
// Semaphore is a classical semaphore synchronization primitive.
// All methods can be safely called on nil Semaphore.
// They will do nothing like you have unlimited semaphore.
Semaphore struct {
mu sync.Mutex
cond sync.Cond
n, lim int
}
)
// NewSemaphore creates a new semaphore with capacity of n.
func NewSemaphore(n int) *Semaphore {
b := &Semaphore{}
b.Reset(n)
return b
}
// Reset resets semaphore capacity.
// But not the current value, which means it can be used
// to update limit on the fly, but it can't be used to reset
// inconsistent semaphore.
func (b *Semaphore) Reset(n int) {
if b == nil {
return
}
defer b.mu.Unlock()
b.mu.Lock()
if b.cond.L == nil {
b.cond.L = &b.mu
}
b.lim = n
}
// Enter critical section.
func (b *Semaphore) Enter() int {
if b == nil {
return 0
}
defer b.mu.Unlock()
b.mu.Lock()
for b.n >= b.lim {
b.cond.Wait()
}
b.n++
return b.n
}
// Exit from critical section.
func (b *Semaphore) Exit() {
if b == nil {
return
}
defer b.mu.Unlock()
b.mu.Lock()
b.n--
b.cond.Signal()
}
// Len is a number of tasks in the critical section.
func (b *Semaphore) Len() int {
if b == nil {
return 0
}
defer b.mu.Unlock()
b.mu.Lock()
return b.n
}
// Cap is a semaphore capacity.
func (b *Semaphore) Cap() int {
if b == nil {
return 0
}
defer b.mu.Unlock()
b.mu.Lock()
return b.lim
}