-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathSynchronousQueueMS.kt
More file actions
85 lines (70 loc) · 2.51 KB
/
Copy pathSynchronousQueueMS.kt
File metadata and controls
85 lines (70 loc) · 2.51 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
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import java.util.concurrent.atomic.AtomicReference
class SynchronousQueueMS<E> : SynchronousQueue<E> {
private val head: AtomicReference<Node>
private val tail: AtomicReference<Node>
init {
val d = Dummy()
head = AtomicReference<Node>(d)
tail = AtomicReference<Node>(d)
}
override suspend fun send(element: E) {
while (true) {
val t = tail.get()
val h = head.get()
if (t == h || t is Sender<*>) {
val res = suspendCoroutine<Unit?> sc@ { cont ->
val newNode = Sender(element, cont)
if (!t.next.compareAndSet(null, newNode)) {
cont.resume(null)
return@sc
}
tail.compareAndSet(t, newNode)
}
if (res != null) return
} else {
val headNext = h.next.get() as? Receiver<E> ?: continue
if (head.compareAndSet(h, headNext)) {
headNext.action.resume(element)
return
}
}
}
}
override suspend fun receive(): E {
while (true) {
val t = tail.get()
val h = head.get()
if (t == h || t is Receiver<*>) {
val res = suspendCoroutine<E?> sc@ { cont ->
val newNode = Receiver(cont)
if (!t.next.compareAndSet(null, newNode)) {
cont.resume(null)
return@sc
}
tail.compareAndSet(t, newNode)
}
if (res != null) return res
} else {
val headNext = h.next.get() as? Sender<E> ?: continue
if (head.compareAndSet(h, headNext)) {
headNext.action.resume(Unit)
return headNext.element
}
}
}
}
private abstract class Node(val next: AtomicReference<Node>)
private class Receiver<E>(
val action: Continuation<E>,
next: AtomicReference<Node> = AtomicReference<Node>()
) : Node(next)
private class Sender<E>(
val element: E,
val action: Continuation<Unit>,
next: AtomicReference<Node> = AtomicReference<Node>()
) : Node(next)
private class Dummy() : Node(AtomicReference<Node>())
}