density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
|
#include <lf_function_queue.h>
Public Types | |
template<typename ELEMENT_COMPLETE_TYPE > | |
using | put_transaction = typename UnderlyingQueue::template put_transaction< ELEMENT_COMPLETE_TYPE > |
template<typename ELEMENT_COMPLETE_TYPE > | |
using | reentrant_put_transaction = typename UnderlyingQueue::template reentrant_put_transaction< ELEMENT_COMPLETE_TYPE > |
using | consume_operation = typename UnderlyingQueue::consume_operation |
using | reentrant_consume_operation = typename UnderlyingQueue::reentrant_consume_operation |
Public Member Functions | |
lf_function_queue () noexcept=default | |
lf_function_queue (lf_function_queue &&i_source) noexcept=default | |
lf_function_queue & | operator= (lf_function_queue &&i_source) noexcept=default |
~lf_function_queue () | |
template<typename ELEMENT_COMPLETE_TYPE > | |
void | push (ELEMENT_COMPLETE_TYPE &&i_source) |
template<typename ELEMENT_COMPLETE_TYPE , typename... CONSTRUCTION_PARAMS> | |
void | emplace (CONSTRUCTION_PARAMS &&...i_construction_params) |
template<typename ELEMENT_TYPE > | |
put_transaction< typename std::decay< ELEMENT_TYPE >::type > | start_push (ELEMENT_TYPE &&i_source) |
template<typename ELEMENT_TYPE , typename... CONSTRUCTION_PARAMS> | |
put_transaction< ELEMENT_TYPE > | start_emplace (CONSTRUCTION_PARAMS &&...i_construction_params) |
template<typename ELEMENT_COMPLETE_TYPE > | |
void | reentrant_push (ELEMENT_COMPLETE_TYPE &&i_source) |
template<typename ELEMENT_COMPLETE_TYPE , typename... CONSTRUCTION_PARAMS> | |
void | reentrant_emplace (CONSTRUCTION_PARAMS &&...i_construction_params) |
template<typename ELEMENT_TYPE > | |
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > | start_reentrant_push (ELEMENT_TYPE &&i_source) |
template<typename ELEMENT_TYPE , typename... CONSTRUCTION_PARAMS> | |
reentrant_put_transaction< ELEMENT_TYPE > | start_reentrant_emplace (CONSTRUCTION_PARAMS &&...i_construction_params) |
template<typename ELEMENT_COMPLETE_TYPE > | |
bool | try_push (progress_guarantee i_progress_guarantee, ELEMENT_COMPLETE_TYPE &&i_source) noexcept(noexcept(m_queue .try_push( i_progress_guarantee, std::forward< ELEMENT_COMPLETE_TYPE >(i_source)))) |
template<typename ELEMENT_COMPLETE_TYPE , typename... CONSTRUCTION_PARAMS> | |
bool | try_emplace (progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept( noexcept(m_queue.template try_emplace< ELEMENT_COMPLETE_TYPE >( i_progress_guarantee, std::forward< CONSTRUCTION_PARAMS >(i_construction_params)...))) |
template<typename ELEMENT_TYPE > | |
put_transaction< typename std::decay< ELEMENT_TYPE >::type > | try_start_push (progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept(noexcept(m_queue .try_start_push( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source)))) |
template<typename ELEMENT_TYPE , typename... CONSTRUCTION_PARAMS> | |
put_transaction< ELEMENT_TYPE > | try_start_emplace (progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept(noexcept(m_queue .template try_start_emplace< ELEMENT_TYPE >( i_progress_guarantee, std::forward< ELEMENT_TYPE >( i_construction_params)...))) |
template<typename ELEMENT_COMPLETE_TYPE > | |
bool | try_reentrant_push (progress_guarantee i_progress_guarantee, ELEMENT_COMPLETE_TYPE &&i_source) noexcept(noexcept(m_queue .try_reentrant_push( i_progress_guarantee, std::forward< ELEMENT_COMPLETE_TYPE >(i_source)))) |
template<typename ELEMENT_COMPLETE_TYPE , typename... CONSTRUCTION_PARAMS> | |
bool | try_reentrant_emplace (progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept(noexcept(m_queue .template try_reentrant_emplace< ELEMENT_COMPLETE_TYPE >( i_progress_guarantee, std::forward< CONSTRUCTION_PARAMS >( i_construction_params)...))) |
template<typename ELEMENT_TYPE > | |
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > | try_start_reentrant_push (progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept(noexcept(m_queue .try_start_reentrant_push( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source)))) |
template<typename ELEMENT_TYPE , typename... CONSTRUCTION_PARAMS> | |
reentrant_put_transaction< ELEMENT_TYPE > | try_start_reentrant_emplace (progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept(noexcept(m_queue .template try_start_reentrant_emplace< ELEMENT_TYPE >( i_progress_guarantee, std::forward< ELEMENT_TYPE >( i_construction_params)...))) |
std::conditional< std::is_void< RET_VAL >::value, bool, optional< RET_VAL > >::type | try_consume (PARAMS...i_params) |
std::conditional< std::is_void< RET_VAL >::value, bool, optional< RET_VAL > >::type | try_consume (consume_operation &i_consume, PARAMS...i_params) |
std::conditional< std::is_void< RET_VAL >::value, bool, optional< RET_VAL > >::type | try_reentrant_consume (PARAMS...i_params) |
std::conditional< std::is_void< RET_VAL >::value, bool, optional< RET_VAL > >::type | try_reentrant_consume (reentrant_consume_operation &i_consume, PARAMS...i_params) |
template<function_type_erasure ERASURE_ = ERASURE, typename std::enable_if< ERASURE_!=function_manual_clear >::type * = nullptr> | |
void | clear () noexcept |
bool | empty () noexcept |
Static Public Attributes | |
static constexpr bool | concurrent_puts = PROD_CARDINALITY == concurrency_multiple |
static constexpr bool | concurrent_consumes = CONSUMER_CARDINALITY == concurrency_multiple |
static constexpr bool | concurrent_put_consumes = true |
static constexpr bool | is_seq_cst = CONSISTENCY_MODEL == consistency_sequential |
Friends | |
void | swap (lf_function_queue &i_first, lf_function_queue &i_second) noexcept |
Heterogeneous FIFO pseudo-container specialized to hold callable objects. lf_function_queue is an adaptor for lf_heter_queue.
CALLABLE | Signature required to the callable objects. Must be in the form RET_VAL (PARAMS...) |
ALLOCATOR_TYPE | Allocator type to be used. This type must satisfy the requirements of both UntypedAllocator and PagedAllocator. The default is density::default_allocator. |
ERASURE | Type erasure to use the callable objects. Must be a member of density::function_type_erasure. |
PROD_CARDINALITY | specifies whether multiple threads can do put transactions concurrently. Must be a member of density::concurrency_cardinality. |
CONSUMER_CARDINALITY | specifies whether multiple threads can do consume operations concurrently. Must be a member of density::concurrency_cardinality. |
CONSISTENCY_MODEL | Specifies whether the queue is linearizable. Must be a member of density::consistency_model. Implementation note: Currently this parameter affects only put operations, and only in case of multiple producers: in case of relaxed consistency model, for a small amount of time, during the first phase of a put transaction, the queue is truncated, so any thread can successfully put further elements, but those elements are not observable to any thread, even the one who did the put. |
If ERASURE == function_manual_clear, lf_function_queue is not able to destroy the callable objects without invoking them. This produces a performance benefit, but:
Thread safeness: A thread doing put operations and another thread doing consumes don't need to be synchronized. If PROD_CARDINALITY is concurrency_multiple, multiple threads are allowed to put without any synchronization. If CONSUMER_CARDINALITY is concurrency_multiple, multiple threads are allowed to consume without any synchronization.
Exception safeness: Any function of lf_function_queue is noexcept or provides the strong exception guarantee.
This class template uses lock-free algorithms for both put operations and consume operations. Anyway, for the overall put or consume to be lock-free, if a memory operation is necessary, it must be lock-free too. The default allocator, density::default_allocator, can manage pages in lock freedom within its current capacity (i.e. the memory it has managed until now). This capacity is composed by all the allocated, pinned, thread-owned and free pages. If the capacity must exceed its previous peek, and all the memory regions are exhausted, default_allocator must request a new memory region to the system. In this case it can't guarantee lock-freedom. The static functions default_allocator::reserve_lockfree_page_memory and default_allocator::try_reserve_lockfree_page_memory can be used to reserve a capacity in advance.
default_allocator delegates legacy memory operations to the system. Since the storage of elements whose size exceeds a fixed limit can't be allocated in a page, they require a legacy memory allocation, and in this case the put can't be lock-free.
This class template provides all the put functions provided by density::function_queue, and furthermore it adds the try_ variants, that:
using put_transaction = typename UnderlyingQueue::template put_transaction<ELEMENT_COMPLETE_TYPE> |
Alias to lf_heter_queue::put_transaction.
using reentrant_put_transaction = typename UnderlyingQueue::template reentrant_put_transaction<ELEMENT_COMPLETE_TYPE> |
using consume_operation = typename UnderlyingQueue::consume_operation |
Alias to lf_heter_queue::consume_operation.
using reentrant_consume_operation = typename UnderlyingQueue::reentrant_consume_operation |
|
defaultnoexcept |
Default constructor.
|
defaultnoexcept |
Move constructor.
|
inline |
Destructor
|
defaultnoexcept |
Move assignment.
|
inline |
Adds at the end of the queue a callable object.
See lf_heter_queue::push for a detailed description.
|
inline |
Adds at the end of the queue a callable object of type ELEMENT_COMPLETE_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
Note: the template argument ELEMENT_COMPLETE_TYPE
can't be deduced from the parameters so it must explicitly specified.
See lf_heter_queue::emplace for a detailed description.
|
inline |
Begins a transaction that appends an element of type ELEMENT_TYPE
, copy-constructing or move-constructing it from the source.
See lf_heter_queue::start_push for a detailed description.
Examples
|
inline |
Begins a transaction that appends an element of a type ELEMENT_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
See lf_heter_queue::start_emplace for a detailed description.
Examples
|
inline |
Adds at the end of the queue a callable object.
See lf_heter_queue::reentrant_push for a detailed description.
|
inline |
Adds at the end of the queue a callable object of type ELEMENT_COMPLETE_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
Note: the template argument ELEMENT_COMPLETE_TYPE
can't be deduced from the parameters so it must explicitly specified.
See lf_heter_queue::reentrant_emplace for a detailed description.
|
inline |
Begins a transaction that appends an element of type ELEMENT_TYPE
, copy-constructing or move-constructing it from the source.
See lf_heter_queue::start_reentrant_push for a detailed description.
Examples
|
inline |
Begins a transaction that appends an element of a type ELEMENT_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
See lf_heter_queue::start_reentrant_emplace for a detailed description.
Examples
|
inlinenoexcept |
Tries to add at the end of the queue a callable object respecting a progress guarantee.
See lf_heter_queue::try_push for a detailed description.
|
inlinenoexcept |
Tries to add at the end of the queue a callable object of type ELEMENT_COMPLETE_TYPE
respecting a progress guarantee, in-place-constructing it from a perfect forwarded parameter pack.
Note: the template argument ELEMENT_COMPLETE_TYPE
can't be deduced from the parameters so it must explicitly specified.
See lf_heter_queue::try_emplace for a detailed description.
|
inlinenoexcept |
Tries to begin a transaction that appends an element of type ELEMENT_TYPE
, copy-constructing or move-constructing it from the source.
See lf_heter_queue::try_start_push for a detailed description.
Examples
|
inlinenoexcept |
Tries to begin a transaction appends an element of a type ELEMENT_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
See lf_heter_queue::try_start_emplace for a detailed description.
Examples
|
inlinenoexcept |
Tries to add at the end of the queue a callable object.
See lf_heter_queue::try_reentrant_push for a detailed description.
|
inlinenoexcept |
Tries to add at the end of the queue a callable object of type ELEMENT_COMPLETE_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
Note: the template argument ELEMENT_COMPLETE_TYPE
can't be deduced from the parameters so it must explicitly specified.
See lf_heter_queue::try_reentrant_emplace for a detailed description.
|
inlinenoexcept |
Tries to begin a transaction appends an element of type ELEMENT_TYPE
, copy-constructing or move-constructing it from the source.
See lf_heter_queue::try_start_reentrant_push for a detailed description.
Examples
|
inlinenoexcept |
Tries to begin a transaction appends an element of a type ELEMENT_TYPE
, in-place-constructing it from a perfect forwarded parameter pack.
See lf_heter_queue::try_start_reentrant_emplace for a detailed description.
Examples
|
inline |
If the queue is not empty, invokes the first function object of the queue and then deletes it from the queue. Otherwise no operation is performed.
i_params... | parameters to be forwarded to the function object |
This function is not reentrant: if the callable object accesses in any way this queue, the behavior is undefined. Use lf_function_queue::try_reentrant_consume if you are not sure about what the callable object may do.
Throws: unspecified
Exception guarantee: strong (in case of exception the function has no observable effects).
|
inline |
If the queue is not empty, invokes the first function object of the queue and then deletes it from the queue. Otherwise no operation is performed.
The consume operation is performed using the provided consume_operation object. If the element to consume is in the same page of the last element visited by the provided consume operation, the implementation does not need to pin page. For this reason this overload of try_consume is much faster than the other.
i_consume | object to use for the consume operation |
i_params... | parameters to be forwarded to the function object |
This function is not reentrant: if the callable object accesses in any way this queue, the behavior is undefined. Use lf_function_queue::try_reentrant_consume if you are not sure about what the callable object may do.
Throws: unspecified
Exception guarantee: strong (in case of exception the function has no observable effects).
|
inline |
If the queue is not empty, invokes the first function object of the queue and then deletes it from the queue. Otherwise no operation is performed.
i_params... | parameters to be forwarded to the function object |
This function is reentrant: the callable object can access in any way this queue.
Throws: unspecified
Exception guarantee: strong (in case of exception the function has no observable effects).
|
inline |
If the queue is not empty, invokes the first function object of the queue and then deletes it from the queue. Otherwise no operation is performed.
The consume operation is performed using the provided consume_operation object. If the element to consume is in the same page of the last element visited by the provided consume operation, the implementation does not need to pin page. For this reason this overload of try_reentrant_consume is much faster than the other.
i_consume | object to use for the consume operation |
i_params... | parameters to be forwarded to the function object |
This function is reentrant: the callable object can access in any way this queue.
Throws: unspecified
Exception guarantee: strong (in case of exception the function has no observable effects).
|
inlinenoexcept |
Deletes all the callable objects in the queue. This function is disabled at compile-time if ERASURE is function_manual_clear.
Effects on iterators : all the iterators are invalidated
Throws: nothing
Complexity: linear.
|
inlinenoexcept |
Returns whether this container is empty
|
friend |
Swaps two function queues.
|
static |
Whether multiple threads can do put operations on the same queue without any further synchronization.
|
static |
Whether multiple threads can do consume operations on the same queue without any further synchronization.
|
static |
Whether puts and consumes can be done concurrently without any further synchronization. In any case unsynchronized concurrency is constrained by concurrent_puts and concurrent_consumes.
|
static |
Whether this queue is sequential consistent.