-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlockless.comp
More file actions
51 lines (40 loc) · 1.15 KB
/
lockless.comp
File metadata and controls
51 lines (40 loc) · 1.15 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
/**
Lock-free stack using atomic compare-and-swap.
Demonstrates retry-based concurrency without locks.
Highlights:
- `atomic.swap` handles the compare-and-swap retry loop, the block describes the
desired next state, the function handles contention
- `forever` with `->?` break creates an infinite loop that terminates on failure,
no while/break keywords needed
- Shape dispatch means `push` and `pop` only accept `~stack` values,
invalid data fails at the call boundary, not somewhere deep in the
implementation
*/
!import atomic comp "atomic"
!shape node ~{value~text next~(node|nil)}
!shape stack ~{head~(node|nil) version~num}
!main console [
{nil 0}
| push "first"
| push "second"
| push "third"
| forever :[
pop | output "Popped: %()" |? break
]
]
/// Push a value onto the stack, retrying on contention
!func push ~stack (
!param value ~text
[$ | atomic.swap :{
head = {value=value next=$.head}
version = $.version + 1
}]
)
/// Pop a value from the stack, retrying on contention
/// Fails if stack is empty
!func pop ~stack [
$ | atomic.swap :{
head = $.head.next
version = $.version + 1
}
]