-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqueue_miso.go
More file actions
99 lines (80 loc) · 1.92 KB
/
queue_miso.go
File metadata and controls
99 lines (80 loc) · 1.92 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
93
94
95
96
97
98
99
package container
import (
"sync/atomic"
)
type iMISOQueueNodePool[T any] interface {
Get() *node[T]
Put(n *node[T])
}
// type MISOQueueNodePool[T any] struct {
// sync.Pool
// }
// func (p *MISOQueueNodePool[T]) Get() *node[T] {
// return p.Pool.Get().(*node[T])
// }
// func (p *MISOQueueNodePool[T]) Put(n *node[T]) {
// p.Pool.Put(n)
// }
// 多进单出的队列,可以在多个goruntine中push,只能在一个goruntine中pop
type MISOQueue[T any] struct {
pool Pool[*node[T]]
head atomic.Pointer[node[T]]
tail atomic.Pointer[node[T]]
zero T // 0值
}
func NewMISOQueue[T any](opt ...MISOQueueOption[T]) *MISOQueue[T] {
q := MISOQueue[T]{}
for _, o := range opt {
o(&q)
}
q.pool = NewPool(func() *node[T] {
return &node[T]{}
})
n := q.pool.Get()
q.head.Store(n)
q.tail.Store(n)
return &q
}
type MISOQueueOption[T any] func(*MISOQueue[T])
// func WithMISOQueueNodePool[T any](pool iMISOQueueNodePool[T]) MISOQueueOption[T] {
// return func(m *MISOQueue[T]) {
// m.pool = pool
// }
// }
// type defMISOQueueNodePool[T any] struct{}
// func (p *defMISOQueueNodePool[T]) Get() *node[T] {
// return &node[T]{}
// }
// func (p *defMISOQueueNodePool[T]) Put(*node[T]) {}
type node[T any] struct {
next atomic.Pointer[node[T]]
val T
}
// Enqueue 将val推入到队列尾部.
// Enqueue 可以在多个goruntine中并发调用
func (q *MISOQueue[T]) Enqueue(val T) {
n := q.pool.Get()
n.val = val
prev := q.tail.Swap(n)
prev.next.Store(n)
}
// Dequeue从队列头将元素弹出,若队列为空,会返回false
// 只能在同一个goruntime调用Dequeue
func (q *MISOQueue[T]) Dequeue() (T, bool) {
head := q.head.Load()
next := head.next.Load()
var v T
if next != nil {
q.head.Store(next)
v = next.val
next.val = q.zero
head.next.Store(nil)
q.pool.Put(head)
return v, true
}
return v, false
}
func (q *MISOQueue[T]) IsEmpty() bool {
head := q.head.Load()
return head.next.Load() == nil
}