|
1 |
| -# Concurrent::Stack |
| 1 | +[](https://github.com/lizmat/Concurrent-Stack/actions) |
2 | 2 |
|
3 |
| -A lock-free stack data structure, safe for concurrent use. |
| 3 | +NAME |
| 4 | +==== |
4 | 5 |
|
5 |
| -## Synopsis |
| 6 | +Concurrent::Stack - A lock-free concurrent stack data structure |
6 | 7 |
|
7 |
| - use Concurrent::Stack; |
| 8 | +SYNOPSIS |
| 9 | +======== |
8 | 10 |
|
9 |
| - my $stack = Concurrent::Stack.new; |
| 11 | +```raku |
| 12 | +use Concurrent::Stack; |
10 | 13 |
|
11 |
| - for 'a'..'z' { |
12 |
| - $stack.push($_); |
13 |
| - } |
| 14 | +my $stack = Concurrent::Stack.new; |
14 | 15 |
|
15 |
| - say $stack.elems; # 26 |
16 |
| - say $stack.peek; # z |
17 |
| - say $stack.pop; # z |
18 |
| - say $stack.pop; # y |
19 |
| - say $stack.peek; # x |
20 |
| - $stack.push('k'); |
21 |
| - say $stack.peek; # k |
22 |
| - say $stack.elems; # 25 |
23 |
| - say $stack.Seq; # A Seq iterating a snapshot of the stack |
24 |
| - say $stack.list; # A lazy List with a snapshot of the stack |
| 16 | +for 'a'..'z' { |
| 17 | + $stack.push($_); |
| 18 | +} |
25 | 19 |
|
26 |
| - $stack.pop for ^25; |
27 |
| - say $stack.elems; # 0 |
28 |
| - my $x = $stack.peek; # Failure with X::Concurrent::Stack::Empty |
29 |
| - my $y = $stack.pop; # Failure with X::Concurrent::Stack::Empty |
| 20 | +say $stack.elems; # 26 |
| 21 | +say $stack.peek; # z |
| 22 | +say $stack.pop; # z |
| 23 | +say $stack.pop; # y |
| 24 | +say $stack.peek; # x |
| 25 | +$stack.push('k'); |
| 26 | +say $stack.peek; # k |
| 27 | +say $stack.elems; # 25 |
| 28 | +say $stack.Seq; # A Seq iterating a snapshot of the stack |
| 29 | +say $stack.list; # A lazy List with a snapshot of the stack |
30 | 30 |
|
31 |
| -## Overview |
| 31 | +$stack.pop for ^25; |
| 32 | +say $stack.elems; # 0 |
| 33 | +my $x = $stack.peek; # Failure with X::Concurrent::Stack::Empty |
| 34 | +my $y = $stack.pop; # Failure with X::Concurrent::Stack::Empty |
| 35 | +``` |
32 | 36 |
|
33 |
| -Lock-free data structures may be safely used from multiple threads, yet do not |
34 |
| -use locks in their implementation. They achieve this through the use of atomic |
35 |
| -operations provided by the hardware. Nothing can make contention between |
36 |
| -threads cheap - synchronization at the CPU level is still synchronization - |
37 |
| -but lock free data structures tend to scale better. |
| 37 | +DESCRIPTION |
| 38 | +=========== |
38 | 39 |
|
39 |
| -This lock-free stack data structure uses a linked list of immutable nodes, the |
40 |
| -only mutable state being a head pointer to the node representing the stack top |
41 |
| -and an element counter mintained through atomic increment/decrement operations. |
42 |
| -The element count updates are not performed as part of the stack update, and so |
43 |
| -may lag the actual state of the stack. However, since checking the number of |
44 |
| -elements to decide whether to `peek` or `pop` is doomed in a concurrent setting |
45 |
| -anyway (since another thread may `pop` the last value in the meantime), this is |
46 |
| -not problematic. The `elems` method primarily exists so that the number of |
47 |
| -elements can be queried once the stack reaches some known stable point (for |
48 |
| -example, when a bunch of working threads that `push` to it are all known to |
49 |
| -have completed their work). |
| 40 | +Lock-free data structures may be safely used from multiple threads, yet do not use locks in their implementation. They achieve this through the use of atomic operations provided by the hardware. Nothing can make contention between threads cheap - synchronization at the CPU level is still synchronization - but lock free data structures tend to scale better. |
50 | 41 |
|
51 |
| -### Methods |
| 42 | +This lock-free stack data structure uses a linked list of immutable nodes, the only mutable state being a head pointer to the node representing the stack top and an element counter mintained through atomic increment/decrement operations. The element count updates are not performed as part of the stack update, and so may lag the actual state of the stack. However, since checking the number of elements to decide whether to `peek` or `pop` is doomed in a concurrent setting anyway (since another thread may `pop` the last value in the meantime), this is not problematic. The `elems` method primarily exists so that the number of elements can be queried once the stack reaches some known stable point (for example, when a bunch of working threads that `push` to it are all known to have completed their work). |
52 | 43 |
|
53 |
| -#### push(Any $value) |
| 44 | +METHODS |
| 45 | +======= |
| 46 | + |
| 47 | +push(Any $value) |
| 48 | +---------------- |
54 | 49 |
|
55 | 50 | Pushes a value onto the stack. Returns the value that was pushed.
|
56 | 51 |
|
57 |
| -#### pop() |
| 52 | +pop() |
| 53 | +----- |
| 54 | + |
| 55 | +If the stack is not empty, removes the top value and returns it. Otherwise, returns a `Failure` containing an exception of typei `X::Concurrent::Stack::Empty`. |
| 56 | + |
| 57 | +peek() |
| 58 | +------ |
| 59 | + |
| 60 | +If the stack is not empty, returns the top value. Otherwise, returns a `Failure` containing an exception of type `X::Concurrent::Stack::Empty`. |
| 61 | + |
| 62 | +elems() |
| 63 | +------- |
| 64 | + |
| 65 | +Returns the number of elements on the stack. This value can only be relied upon when it is known that no threads are pushing/popping from the stack at the point this method is called. **Never** use the result of `elems` to decide whether to `peek` or `pop`, since another thread may `pop` in the meantime. Instead, check if `peek` or `pop` return a `Failure`. |
| 66 | + |
| 67 | +head2 Bool() |
| 68 | + |
| 69 | +Returns `False` if the stack is empty and `True` if the stack is non-empty. The result can only be relied upon when it is known that no threads are pushing/popping from the stack at the point this method is called. **Never** use the result of `Bool` to decide whether to `peek` or `pop`, since another thread may `pop` in the meantime. Instead, check if `peek` or `pop` return a `Failure`. |
58 | 70 |
|
59 |
| -If the stack is not empty, removes the top value and returns it. Otherwise, |
60 |
| -returns a `Failure` containing an exception of type `X::Concurrent::Stack::Empty`. |
| 71 | +Seq() |
| 72 | +----- |
61 | 73 |
|
62 |
| -#### peek() |
| 74 | +Returns a `Seq` that will iterate to a snapshot of the stack content, starting from the stack top. The snapshot is made at the time this method is called. |
63 | 75 |
|
64 |
| -If the stack is not empty, returns the top value. Otherwise, returns a `Failure` |
65 |
| -containing an exception of type `X::Concurrent::Stack::Empty`. |
| 76 | +list() |
| 77 | +------ |
66 | 78 |
|
67 |
| -#### elems() |
| 79 | +Returns a `List` that will lazily evaluate to a snapshot of the stack content, starting from the stack top. The snapshot is made at the time this method is called. |
68 | 80 |
|
69 |
| -Returns the number of elements on the stack. This value can only be relied upon |
70 |
| -when it is known that no threads are pushing/popping from the stack at the |
71 |
| -point this method is called. Never use the result of `elems` to decide whether |
72 |
| -to `peek` or `pop`, since another thread may `pop` in the meantime. Instead, |
73 |
| -check if `peek` or `pop` return a `Failure`. |
| 81 | +AUTHOR |
| 82 | +====== |
74 | 83 |
|
75 |
| -#### Bool() |
| 84 | +Jonathan Worthington |
76 | 85 |
|
77 |
| -Returns `False` if the stack is empty and `True` if the stack is non-empty. |
78 |
| -The result can only be relied upon when it is known that no threads are |
79 |
| -pushing/popping from the stack at the point this method is called. Never use |
80 |
| -the result of `Bool` to decide whether to `peek` or `pop`, since another |
81 |
| -thread may `pop` in the meantime. Instead, check if `peek` or `pop` return a |
82 |
| -`Failure`. |
| 86 | +COPYRIGHT AND LICENSE |
| 87 | +===================== |
83 | 88 |
|
84 |
| -#### Seq() |
| 89 | +Copyright 2018 - 2024 Raku Community |
85 | 90 |
|
86 |
| -Returns a `Seq` that will iterate to a snapshot of the stack content, |
87 |
| -starting from the stack top. The snapshot is made at the time this |
88 |
| -method is called. |
| 91 | +Copyright 2024 Raku Community |
89 | 92 |
|
90 |
| -#### list() |
| 93 | +This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0. |
91 | 94 |
|
92 |
| -Returns a `List` that will lazily evaluate to a snapshot of the stack |
93 |
| -content, starting from the stack top. The snapshot is made at the time |
94 |
| -this method is called. |
0 commit comments