Struct cordyceps::stack::TransferStack
source · pub struct TransferStack<T: Linked<Links<T>>> { /* private fields */ }
Expand description
An intrusive lock-free singly-linked FIFO stack, where all entries currently in the stack are consumed in a single atomic operation.
A transfer stack is perhaps the world’s simplest lock-free concurrent data structure. It provides two primary operations:
-
TransferStack::push
, which appends an element to the end of the transfer stack, -
TransferStack::take_all
, which atomically takes all elements currently on the transfer stack and returns them as a new mutableStack
.
These are both O(1) operations, although push
performs a
compare-and-swap loop that may be retried if another producer concurrently
pushed an element.
In order to be part of a TransferStack
, a type T
must implement
the Linked
trait for stack::Links<T>
.
Pushing elements into a TransferStack
takes ownership of those elements
through an owning Handle
type. Dropping a
TransferStack
drops all elements currently linked into the stack.
A transfer stack is often useful in cases where a large number of resources
must be efficiently transferred from several producers to a consumer, such
as for reuse or cleanup. For example, a TransferStack
can be used as the
“thread” (shared) free list in a mimalloc
-style sharded
allocator, with a mutable Stack
used as the local
(unsynchronized) free list. When an allocation is freed from the same CPU
core that it was allocated on, it is pushed to the local free list, using an
unsynchronized mutable Stack::push
operation. If an allocation is freed
from a different thread, it is instead pushed to that thread’s shared free
list, a TransferStack
, using an atomic TransferStack::push
operation. New allocations are popped from the local unsynchronized free
list, and if the local free list is empty, the entire shared free list is
moved onto the local free list. This allows objects which do not leave the
CPU core they were allocated on to be both allocated and deallocated using
unsynchronized operations, and new allocations only perform an atomic
operation when the local free list is empty.
Implementations§
source§impl<T> TransferStack<T>
impl<T> TransferStack<T>
sourcepub const fn new() -> Self
Available on non-loom
only.
pub const fn new() -> Self
loom
only.Returns a new TransferStack
with no elements.
sourcepub fn push(&self, element: T::Handle)
pub fn push(&self, element: T::Handle)
Pushes element
onto the end of this TransferStack
, taking ownership
of it.
This is an O(1) operation, although it performs a compare-and-swap
loop that may repeat if another producer is concurrently calling push
on the same TransferStack
.
This takes ownership over element
through its owning Handle
type. If the TransferStack
is dropped before the
pushed element
is removed from the stack, the element
will be dropped.