carb::container::LocklessQueue
Defined in carb/container/LocklessQueue.h
-
template<class T, LocklessQueueLink<T> T::* U>
class LocklessQueue Implements a lockless queue: a FIFO queue that is thread-safe yet requires no kernel synchronization.
LocklessQueue is designed to be easy-to-use. For a class
Foo
that you want to be contained in a LocklessQueue, it must have a member of type LocklessQueueLink<Foo>. This member is what the LocklessQueue will use for tracking data.Pushing to LocklessQueue is simply done through LocklessQueue::push(), which is entirely thread-safe. LocklessQueue ensures first-in-first-out (FIFO) for each producer pushing to LocklessQueue. Multiple producers may be pushing into LocklessQueue simultaneously, so their items can become mingled, but each producer’s pushed items will be strongly ordered.
Popping on the other hand is different for single-consumer vs. multiple-consumer. For single-consumer (via the LocklessQueue::popSC() function) only one thread may be popping from LocklessQueue at any given time. It is up to the caller to ensure this mutual exclusivity.
If multiple-consumer is desired, use the LocklessQueue::popMC() function; it ensures additional thread safety and is therefore higher cost. Furthermore LocklessQueue::popMC() has a contention back-off capability that will attempt to solve high-contention situations with progressive spin and sleep if absolutely necessary.
Simple example:
class Foo { public: LocklessQueueLink<Foo> m_link; }; LocklessQueue<Foo, &Foo::m_link> queue; queue.push(new Foo); Foo* p = queue.popSC(); delete p;
- Thread Safety
LocklessQueue is entirely thread-safe except where declared otherwise. No allocation happens with a LocklessQueue; instead the caller is responsible for construction/destruction of contained objects.
- Template Parameters
T – The type to contain.
U – A pointer-to-member of a LocklessQueueLink member within T (see above example).
Public Functions
-
inline constexpr LocklessQueue()
Constructs a new LocklessQueue.
-
inline LocklessQueue(LocklessQueue &&rhs)
LocklessQueue is partially movable in that it can be move-constructed from another LocklessQueue, but cannot be move-assigned.
This is to guarantee that the state of the receiving LocklessQueue is a fresh state.
-
LocklessQueue &operator=(LocklessQueue&&) = delete
Cannot move-assign, only move-construct.
This is to guarantee the state of the receiving LocklessQueue is a fresh state.
-
inline ~LocklessQueue()
Destructor.
Warning
Asserts that isEmpty() returns
true
.
-
inline bool isEmpty() const
Indicates whether the queue is empty.
Warning
Another thread may have modified the LocklessQueue before this function returns.
- Returns
true
if the queue appears empty;false
if items appear to exist in the queue.
-
inline bool push(T *p)
Pushes an entry onto the LocklessQueue.
- Parameters
p – The item to push into the queue.
- Returns
true
if the queue was empty prior to push;false
otherwise. Note that this is atomically correct as opposed to calling isEmpty() before push().
-
template<class InputItRef>
inline bool push(InputItRef begin, InputItRef end) Pushes a contiguous block of entries from [
begin
,end
) onto the queue.Note
All of the entries are guaranteed to remain strongly ordered and will not be interspersed with entries from other threads.
- Parameters
begin – An InputIterator of the first item to push.
*begin
must resolve to aT&
.end – An off-the-end InputIterator after the last item to push.
- Returns
true if the queue was empty prior to push;
false
otherwise. Note that this is atomically correct as opposed to calling isEmpty() before push().
-
template<class InputItPtr>
inline bool push(InputItPtr begin, InputItPtr end) Pushes a block of pointers-to-entries from [
begin
,end
) onto the queue.Note
All of the entries are guaranteed to remain strongly ordered and will not be interspersed with entries from other threads.
- Parameters
begin – An InputIterator of the first item to push.
*begin
must resolve to aT*
.end – An off-the-end InputIterator after the last item to push.
- Returns
true if the queue was empty prior to push;
false
otherwise. Note that this is atomically correct as opposed to calling isEmpty() before push().
-
inline LocklessQueue eject()
Ejects all entries from this queue as a new LocklessQueue.
Note
To clear all items use popAll().
-
inline void steal(LocklessQueue &rhs)
Atomically steals all entries from another LocklessQueue and adds them to *this.
Effectively pops everything from
rhs
and then pushes everything to*this
. This can be done in two steps though since everything is already linked together: first the head/tail ofrhs
are exchanged withnullptr
in a multi-consumer manner, then since everything is already linked together they can be pushed as one group onto the end of*this
. Therefore, this is much quicker than a loop that pops from one queue and pushes to another.- Parameters
rhs – A LocklessQueue to atomically steal all entries from.
-
inline void popAll()
Empties the queue.
Note
To perform an action on each item as it is popped, use forEach() instead.
-
template<class Func>
inline void forEach(Func &&f) Pops all available items from the queue calling an invocable object on each.
First, pops all available items from
*this
and then callsf
on each.Note
As the pop is the first thing that happens, any new entries that get pushed while the function is executing will NOT be popped and will remain in LocklessQueue when this function returns.
- Parameters
f – An invocable object that accepts a
T*
parameter. Called for each item that was popped from the queue.
-
inline T *popSC()
Pop first entry (Single-consumer).
- Thread Safety
May only be done in a single thread and is mutually exclusive with all other functions that modify LocklessQueue except push(). Use popMC() for a thread-safe pop function.
Warning
Debug builds will assert if a thread safety issue is detected.
- Returns
the first item removed from the queue, or
nullptr
if the queue is empty.
-
inline T *popMC()
Pop first entry (Multiple-consumer).
popSC() is the single-consumer variant of this function and performs better in a single-consumer environment.
Note
In a highly-contentious situation, this function will back off and attempt to sleep in order to resolve the contention.
- Returns
the first item removed from the queue, or
nullptr
if the queue is empty.
-
inline T *pop()
Pop first entry (Multiple-consumer).
popSC() is the single-consumer variant of this function and performs better in a single-consumer environment.
Note
In a highly-contentious situation, this function will back off and attempt to sleep in order to resolve the contention.
- Returns
the first item removed from the queue, or
nullptr
if the queue is empty.
-
inline bool pushNotify(T *p)
Pushes an item onto the queue and notifies a waiting listener.
Equivalent to doing
auto b = push(p); notifyOne(); return b;
.See also
push(), notifyOne()
- Parameters
p – The item to push.
- Returns
true
if LocklessQueue was empty prior to push;false
otherwise. Note that this is atomically correct as opposed to calling isEmpty() before push().
-
inline T *popSCWait()
Blocks the calling thread until an item is available and returns it (Single-consumer).
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popSC(), wait()
- Thread Safety
May only be done in a single thread and is mutually exclusive with all other functions that modify LocklessQueue except push(). Use popMC() for a thread-safe pop function.
Warning
Debug builds will assert if a thread safety issue is detected.
- Returns
The first item popped from the queue.
-
template<class Rep, class Period>
inline T *popSCWaitFor(const std::chrono::duration<Rep, Period> &dur) Blocks the calling thread until an item is available and returns it (Single-consumer) or a timeout elapses.
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popSC(), waitFor()
- Thread Safety
May only be done in a single thread and is mutually exclusive with all other functions that modify LocklessQueue except push(). Use popMC() for a thread-safe pop function.
Warning
Debug builds will assert if a thread safety issue is detected.
- Parameters
dur – The duration to wait for an item to become available.
- Returns
The first item popped from the queue or
nullptr
if the timeout period elapses.
-
template<class Clock, class Duration>
inline T *popSCWaitUntil(const std::chrono::time_point<Clock, Duration> &tp) Blocks the calling thread until an item is available and returns it (Single-consumer) or the clock reaches a time point.
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popSC(), waitUntil()
- Thread Safety
May only be done in a single thread and is mutually exclusive with all other functions that modify LocklessQueue except push(). Use popMC() for a thread-safe pop function.
Warning
Debug builds will assert if a thread safety issue is detected.
- Parameters
tp – The time to wait until for an item to become available.
- Returns
The first item popped from the queue or
nullptr
if the timeout period elapses.
-
inline T *popMCWait()
Blocks the calling thread until an item is available and returns it (Multiple-consumer).
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popMC(), wait()
Note
In a highly-contentious situation, this function will back off and attempt to sleep in order to resolve the contention.
- Returns
the first item removed from the queue.
-
template<class Rep, class Period>
inline T *popMCWaitFor(const std::chrono::duration<Rep, Period> &dur) Blocks the calling thread until an item is available and returns it (Multiple-consumer) or a timeout elapses.
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popMC(), waitFor()
Note
In a highly-contentious situation, this function will back off and attempt to sleep in order to resolve the contention.
- Parameters
dur – The duration to wait for an item to become available.
- Returns
the first item removed from the queue or
nullptr
if the timeout period elapses.
-
template<class Clock, class Duration>
inline T *popMCWaitUntil(const std::chrono::time_point<Clock, Duration> &tp) Blocks the calling thread until an item is available and returns it (Multiple-consumer) or the clock reaches a time point.
Requires the item to be pushed with pushNotify(), notifyOne() or notifyAll().
See also
popMC(), waitUntil()
Note
In a highly-contentious situation, this function will back off and attempt to sleep in order to resolve the contention.
- Parameters
tp – The time to wait until for an item to become available.
- Returns
the first item removed from the queue or
nullptr
if the timeout period elapses.
-
inline void wait()
Waits until the queue is non-empty.
Note
Requires notification that the queue is non-empty, such as from pushNotify(), notifyOne() or notifyAll().
Note
Though wait() returns, another thread may have popped the available item making the queue empty again. Use popSCWait() / popMCWait() if it is desired to ensure that the current thread can obtain an item.
-
template<class Rep, class Period>
inline bool waitFor(const std::chrono::duration<Rep, Period> &dur) Waits until LocklessQueue is non-empty or a specified duration has passed.
Note
Though waitFor() returns
true
, another thread may have popped the available item making the queue empty again. Use popSCWaitFor() / popMCWaitFor() if it is desired to ensure that the current thread can obtain an item.Note
Requires notification that the queue is non-empty, such as from pushNotify(), notifyOne() or notifyAll().
- Parameters
dur – The duration to wait for an item to become available.
- Returns
true
if an item appears to be available;false
if the timeout elapses.
-
template<class Clock, class Duration>
inline bool waitUntil(const std::chrono::time_point<Clock, Duration> &tp) Waits until LocklessQueue is non-empty or a specific time is reached.
Note
Though waitUntil() returns
true
, another thread may have popped the available item making the queue empty again. Use popSCWaitUntil() / popMCWaitUntil() if it is desired to ensure that the current thread can obtain an item.Note
Requires notification that the queue is non-empty, such as from pushNotify(), notifyOne() or notifyAll().
- Parameters
tp – The time to wait until for an item to become available.
- Returns
true
if an item appears to be available;false
if the time is reached.
-
inline void notifyOne()
Notifies a single waiting thread.
Notifies a single thread waiting in wait(), waitFor(), waitUntil(), popSCWait(), popMCWait(), popSCWaitFor(), popMCWaitFor(), popSCWaitUntil(), or popMCWaitUntil() to wake and check the queue.
-
inline void notifyAll()
Notifies all waiting threads.
Notifies all threads waiting in wait(), waitFor(), waitUntil(), popSCWait(), popMCWait(), popSCWaitFor(), popMCWaitFor(), popSCWaitUntil(), or popMCWaitUntil() to wake and check the queue.