Concurrent Queue - SeqAn API Documentation

# Class Concurrent Queue
Thread-safe queue for multiple producers and multiple consumers.

All Subcl's | ConcurrentSuspendableQueue
Defined in | <seqan/parallel.h>
Signature | `template <typename TValue, typename TSpec> class ConcurrentQueue;`

## Template Parameters

`TValue` | Element type of the queue.
`TSpec` | Tag for further specializing the Concurrent Queue. Default is `void`.

## Interface Function Overview

- `void appendValue(queue, val[, expandTag[, parallelTag]);`
  Enqueue a value to a queue.
- `TSize capacity(queue);`
  Returns the capacity of a queue.
- `bool empty(queue);`
  Returns whether a queue is empty.
- `TSize length(queue);`
  Returns the size of a queue.
- `void lockReading(queue);`
  Register a reader.
- `void lockWriting(queue);`
  Register a writer.
- `bool popFront(result, queue[, parallelTag]);`
  Dequeue a value from a queue.
- `TValue popFront(queue[, parallelTag]);`
  Dequeue a value from a queue.
- `bool tryPopFront(result, queue[, parallelTag]);`
  Try to dequeue a value from a queue.
- `void unlockReading(queue);`
  Deregister a reader.
- `void unlockWriting(queue);`
  Deregister a writer.
- `void waitForFirstValue(queue);`
  Wait for writers to enqueue the first value.
- `void waitForWriters(queue, writerCount);`
  Wait for writers to register.

## Detailed Description

The Concurrent Queue is a thread-safe FIFO queue that supports multiple producers and multiple consumers (MPMC). Elements are enqueued via appendValue and dequeued with tryPopFront or popFront. Depending on the expansion tag of appendValue it can grow dynamically or have a fixed size.

The implementation is lock-free and uses a @Class.AllocString@ as ring buffer.

### Examples

Simple example for a single producer single consumer (SPSC) dynamic queue.

    #include <iostream>
    #include <seqan/parallel.h>

    using namespace seqan2;

    int main()
    {
        // instantiate an empty Queue
        ConcurrentQueue<unsigned> queue;

        // start two threads
        SEQAN_OMP_PRAGMA(parallel sections num_threads(2))
        {
            SEQAN_OMP_PRAGMA(section)
            {
                for (unsigned i = 9999; i != 0; --i)
                    appendValue(queue, i);
            }

            SEQAN_OMP_PRAGMA(section)
            {
                bool equal = true;
                for (unsigned i = 9999; i != 0; --i)
                    equal &= (i == popFront(queue));
                std::cout << (equal ? "SUCCESS" : "FAILURE") << std::endl;
            }
        }

        return 0;
    }

Demo: demos/dox/parallel/queue_example.cpp

The output is:

    SUCCESS

## Interface Functions Detail

### `void appendValue(queue, val[, expandTag[, parallelTag]);`

Enqueue a value to a queue.

#### Parameters

`queue` | A queue.
`val` | The value to enqueue.
`expandTag` | The overflow strategy. If Generous the queue will be automatically resized if the capacity is exceeded, otherwise the thread spinlocks until the element can be enqueued. Default is the DefaultOverflowImplicit result for the `queue` type.
`parallelTag` | The concurrency scheme. If multiple threads enqueue values concurrently this tag must be Parallel. The more efficient Serial tag can only be used if one thread calls `appendValue` at a time. Default is Parallel.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `TSize capacity(queue);`

Returns the capacity of a queue.

#### Parameters

`queue` | The queue to query for its capacity.

#### Returns

`TSize` | Returns the capacity of the queue.

The capacity is the number of elements that can be enqueued at the same time without reallocating memory.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `bool empty(queue);`

Returns whether a queue is empty.

#### Parameters

`queue` | The queue to query.

#### Returns

`bool` | Whether or not the queue is empty.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `TSize length(queue);`

Returns the size of a queue.

#### Parameters

`queue` | The queue to query for its size.

#### Returns

`TSize` | The number of elements in the queue.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void lockReading(queue);`

Register a reader.

#### Parameters

`queue` | The queue to register a reader at.

The destructor of the queue will spinlock until all readers are deregistered.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void lockWriting(queue);`

Register a writer.

#### Parameters

`queue` | The queue to register a writer at.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `bool popFront(result, queue[, parallelTag]);`

Dequeue a value from a queue.

#### Parameters

`queue` | A queue.
`result` | The dequeued value. If the queue is empty but writers are available the thread spinlocks until a value becomes available.
`parallelTag` | The concurrency scheme. If multiple threads dequeue values concurrently this tag must be Parallel. The more efficient Serial tag can only be used if one thread calls `popFront` at a time. Default is Parallel.

#### Returns

`bool` | Returns `true` if a value could be dequeued or `false` if no writer is available, see waitForWriters.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `TValue popFront(queue[, parallelTag]);`

Dequeue a value from a queue.

#### Parameters

`queue` | A queue.
`parallelTag` | The concurrency scheme. If multiple threads dequeue values concurrently this tag must be Parallel. The more efficient Serial tag can only be used if one thread calls `popFront` at a time. Default is Parallel.

#### Returns

`TValue` | The dequeued value. If the queue is empty the thread spinlocks until a value becomes available.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `bool tryPopFront(result, queue[, parallelTag]);`

Try to dequeue a value from a queue.

#### Parameters

`queue` | A queue.
`result` | The dequeued value (if available).
`parallelTag` | The concurrency scheme. If multiple threads dequeue values concurrently this tag must be Parallel. The more efficient Serial tag can only be used if one thread calls `popFront` at a time. Default is Parallel.

#### Returns

`bool` | Returns `true` if a value could be dequeued and `false` otherwise.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void unlockReading(queue);`

Deregister a reader.

#### Parameters

`queue` | The queue to deregister a reader from.

The destructor of the queue will spinlock until all readers are deregistered.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void unlockWriting(queue);`

Deregister a writer.

#### Parameters

`queue` | The queue to deregister a writer from.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void waitForFirstValue(queue);`

Wait for writers to enqueue the first value.

#### Parameters

`queue` | A queue.

If the values are dequeued with popFront2, this function is a barrier for all readers to wait until all writers are set up completely and should be called before calling popFront2 the first time.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

### `void waitForWriters(queue, writerCount);`

Wait for writers to register.

#### Parameters

`queue` | A queue.
`writerCount` | The minimal required number of registered writers, see lockWriting.

If the values are dequeued with popFront2, this function is a barrier for all writers to set up completely and should be called before calling appendValue the first time.

#### Data Races

If not stated otherwise, concurrent invocation is not guaranteed to be thread-safe.

#### Dox Sources

    /*!
     * @class ConcurrentQueue Concurrent Queue
     *
     * @headerfile <seqan/parallel.h>
     *
     * @brief Thread-safe queue for multiple producers and multiple consumers.
     *
     * @signature template <typename TValue, typename TSpec> class ConcurrentQueue;
     *
     * @tparam TValue Element type of the queue.
     * @tparam TSpec Tag for further specializing the Concurrent Queue. Default is
     *               <tt>void</tt>.
     *
     * The Concurrent Queue is a thread-safe FIFO queue that supports multiple
     * producers and multiple consumers (MPMC). Elements are enqueued via @link
     * ConcurrentQueue#appendValue @endlink and dequeued with @link
     * ConcurrentQueue#tryPopFront @endlink or @link ConcurrentQueue#popFront
     * @endlink. Depending on the expansion tag of appendValue it can grow
     * dynamically or have a fixed size.
     *
     * The implementation is lock-free and uses a @Class.AllocString@ as ring
     * buffer.
     *
     * @section Examples
     *
     * Simple example for a single producer single consumer (SPSC) dynamic queue.
     *
     * @include demos/dox/parallel/queue_example.cpp
     *
     * The output is:
     *
     * @include demos/dox/parallel/queue_example.cpp.stdout
     *
     *
     *
     * @fn ConcurrentQueue#lockReading
     *
     * @brief Register a reader.
     *
     * @signature void lockReading(queue);
     *
     * @param[in] queue The queue to register a reader at.
     *
     * The destructor of the queue will spinlock until all readers are deregistered.
     *
     * @fn ConcurrentQueue#unlockReading
     *
     * @brief Deregister a reader.
     *
     * @signature void unlockReading(queue);
     *
     * @param[in] queue The queue to deregister a reader from.
     *
     * The destructor of the queue will spinlock until all readers are deregistered.
     *
     * @fn ConcurrentQueue#lockWriting
     *
     * @brief Register a writer.
     *
     * @signature void lockWriting(queue);
     *
     * @param[in] queue The queue to register a writer at.
     *
     *
     *
     * @fn ConcurrentQueue#unlockWriting
     *
     * @brief Deregister a writer.
     *
     * @signature void unlockWriting(queue);
     *
     * @param[in] queue The queue to deregister a writer from.
     *
     *
     *
     * @fn ConcurrentQueue#empty
     *
     * @brief Returns whether a queue is empty.
     *
     * @signature bool empty(queue);
     *
     * @param[in] queue The queue to query.
     *
     * @return bool Whether or not the queue is empty.
     *
     * @fn ConcurrentQueue#length
     *
     * @brief Returns the size of a queue.
     *
     * @signature TSize length(queue);
     *
     * @param[in] queue The queue to query for its size.
     *
     * @return TSize The number of elements in the queue.
     *
     * @fn ConcurrentQueue#capacity
     *
     * @brief Returns the capacity of a queue.
     *
     * @signature TSize capacity(queue);
     *
     * @param[in] queue The queue to query for its capacity.
     *
     * @return TSize Returns the capacity of the queue.
     *
     * The capacity is the number of elements that can be enqueued at the same time
     * without reallocating memory.
     *
     * @fn ConcurrentQueue#tryPopFront
     *
     * @headerfile <seqan/parallel.h>
     *
     * @brief Try to dequeue a value from a queue.
     *
     * @signature bool tryPopFront(result, queue[, parallelTag]);
     *
     * @param[in,out] queue A queue.
     * @param[out] result The dequeued value (if available).
     * @param[in] parallelTag The concurrency scheme. If multiple threads dequeue
     *                        values concurrently this tag must be @link
     *                        ParallelismTags#Parallel @endlink. The more efficient
     *                        @link ParallelismTags#Serial @endlink tag can only be
     *                        used if one thread calls <tt>popFront</tt> at a time.
     *                        Default is @link ParallelismTags#Parallel @endlink.
     *
     * @return bool Returns <tt>true</tt> if a value could be dequeued and
     *              <tt>false</tt> otherwise.
     *
     * @fn ConcurrentQueue#waitForWriters
     *
     * @brief Wait for writers to register.
     *
     * @signature void waitForWriters(queue, writerCount);
     *
     * @param[in] queue A queue.
     * @param[in] writerCount The minimal required number of registered writers, see
     *                        @link ConcurrentQueue#lockWriting @endlink.
     *
     * If the values are dequeued with @link ConcurrentQueue#popFront2 @endlink,
     * this function is a barrier for all writers to set up completely and should be
     * called before calling @link ConcurrentQueue#appendValue @endlink the first
     * time.
     *
     * @fn ConcurrentQueue#waitForFirstValue
     *
     * @brief Wait for writers to enqueue the first value.
     *
     * @signature void waitForFirstValue(queue);
     *
     * @param[in] queue A queue.
     *
     * If the values are dequeued with @link ConcurrentQueue#popFront2 @endlink,
     * this function is a barrier for all readers to wait until all writers are set
     * up completely and should be called before calling @link
     * ConcurrentQueue#popFront2 @endlink the first time.
     *
     * @fn ConcurrentQueue#popFront
     *
     * @headerfile <seqan/parallel.h>
     *
     * @brief Dequeue a value from a queue.
     *
     * @signature bool popFront(result, queue[, parallelTag]);
     *
     * @param[in,out] queue A queue.
     * @param[out] result The dequeued value. If the queue is empty but writers are
     *                    available the thread spinlocks until a value becomes
     *                    available.
     * @param[in] parallelTag The concurrency scheme. If multiple threads dequeue
     *                        values concurrently this tag must be @link
     *                        ParallelismTags#Parallel @endlink. The more efficient
     *                        @link ParallelismTags#Serial @endlink tag can only be
     *                        used if one thread calls <tt>popFront</tt> at a time.
     *                        Default is @link ParallelismTags#Parallel @endlink.
     *
     * @return bool Returns <tt>true</tt> if a value could be dequeued or
     *              <tt>false</tt> if no writer is available, see @link
     *              ConcurrentQueue#waitForWriters @endlink.
     *
     * @fn ConcurrentQueue#popFront2
     *
     * @headerfile <seqan/parallel.h>
     *
     * @brief Dequeue a value from a queue.
     *
     * @signature TValue popFront(queue[, parallelTag]);
     *
     * @param[in,out] queue A queue.
     * @param[in] parallelTag The concurrency scheme. If multiple threads dequeue
     *                        values concurrently this tag must be @link
     *                        ParallelismTags#Parallel @endlink. The more efficient
     *                        @link ParallelismTags#Serial @endlink tag can only be
     *                        used if one thread calls <tt>popFront</tt> at a time.
     *                        Default is @link ParallelismTags#Parallel @endlink.
     *
     * @return TValue The dequeued value. If the queue is empty the thread spinlocks
     *                until a value becomes available.
     *
     * @fn ConcurrentQueue#appendValue
     *
     * @headerfile <seqan/parallel.h>
     *
     * @brief Enqueue a value to a queue.
     *
     * @signature void appendValue(queue, val[, expandTag[, parallelTag]);
     *
     * @param[in,out] queue A queue.
     * @param[in] val The value to enqueue.
     * @param[in] expandTag The overflow strategy. If @link
     *                      OverflowStrategyTags#Generous @endlink the queue will be
     *                      automatically resized if the capacity is exceeded,
     *                      otherwise the thread spinlocks until the element can be
     *                      enqueued. Default is the @link DefaultOverflowImplicit
     *                      @endlink result for the <tt>queue</tt> type.
     * @param[in] parallelTag The concurrency scheme. If multiple threads enqueue
     *                        values concurrently this tag must be @link
     *                        ParallelismTags#Parallel @endlink. The more efficient
     *                        @link ParallelismTags#Serial @endlink tag can only be
     *                        used if one thread calls <tt>appendValue</tt> at a
     *                        time. Default is @link ParallelismTags#Parallel
     *                        @endlink.
     */