-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathtwolock_queue.go
51 lines (45 loc) · 1012 Bytes
/
twolock_queue.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
package queue
import (
"sync"
)
// CQueue is a concurrent unbounded queue which uses two-Lock concurrent queue qlgorithm.
type CQueue[T any] struct {
head *cnode[T]
tail *cnode[T]
hlock sync.Mutex
tlock sync.Mutex
}
type cnode[T any] struct {
value T
next *cnode[T]
}
// NewCQueue returns an empty CQueue.
func NewCQueue[T any]() *CQueue[T] {
n := &cnode[T]{}
return &CQueue[T]{head: n, tail: n}
}
// Enqueue puts the given value v at the tail of the queue.
func (q *CQueue[T]) Enqueue(v T) {
n := &cnode[T]{value: v}
q.tlock.Lock()
q.tail.next = n // Link node at the end of the linked list
q.tail = n // Swing Tail to node
q.tlock.Unlock()
}
// Dequeue removes and returns the value at the head of the queue.
// It returns nil if the queue is empty.
func (q *CQueue[T]) Dequeue() T {
var t T
q.hlock.Lock()
n := q.head
newHead := n.next
if newHead == nil {
q.hlock.Unlock()
return t
}
v := newHead.value
newHead.value = t
q.head = newHead
q.hlock.Unlock()
return v
}