c++-gtk-utils
Public Types | Public Member Functions
Cgu::AsyncQueue< T, Container > Class Template Reference

A thread-safe asynchronous queue. More...

#include <c++-gtk-utils/async_queue.h>

List of all members.

Public Types

typedef Container::value_type value_type
typedef Container::size_type size_type
typedef Container container_type

Public Member Functions

void push (const value_type &obj)
void push (value_type &&obj)
template<class... Args>
void emplace (Args &&...args)
void pop (value_type &obj)
void pop ()
bool empty () const
size_type size () const
void swap (AsyncQueue &other)
AsyncQueueoperator= (const AsyncQueue &rhs)
AsyncQueueoperator= (AsyncQueue &&rhs)
 AsyncQueue ()
 AsyncQueue (AsyncQueue &&rhs)
 AsyncQueue (const AsyncQueue &rhs)
 ~AsyncQueue ()

Detailed Description

template<class T, class Container = std::list<T>>
class Cgu::AsyncQueue< T, Container >

A thread-safe asynchronous queue.

See also:
AsyncQueueDispatch AsyncResult

AsyncQueue is a class which provides some of the functionality of a std::queue object (but note that the AsyncQueue::pop(value_type& obj) method provides the pop()ed element by reference - see the comments on that method for the reason), except that it has mutex locking of the data container so as to permit push()ing and pop()ing from different threads. It is therefore useful for passing data between threads, perhaps in response to a signal being emitted from a Notifier object. Passing the data by means of a SharedLockPtr object, or an IntrusivePtr object referencing data derived from IntrusiveLockCounter, would be ideal.

By default the queue uses a std::list object as its container because in the kind of use mentioned above it is unlikely to hold many objects but it can be changed to, say, a std::deque object by specifying it as the second template parameter.

If the library is installed using the –with-glib-memory-slices-compat or –with-glib-memory-slices-no-compat configuration options, any AsyncQueue objects constructed on free store will be constructed in glib memory slices. This does not affect the queue container itself: to change the allocator of the C++ container, a custom allocator type can be provided when the AsyncQueue object is instantiated offering the standard allocator interface. If glib memory slices are not used or no AsyncQueue objects are constructed on free store, it is not necessary to call g_thread_init() before manipulating or using an AsyncQueue object in multiple threads, but prior to glib version 2.32 glib itself (and thus glib memory slices) are not thread safe unless that function has been called.


Member Typedef Documentation

template<class T, class Container = std::list<T>>
typedef Container Cgu::AsyncQueue< T, Container >::container_type
template<class T, class Container = std::list<T>>
typedef Container::size_type Cgu::AsyncQueue< T, Container >::size_type
template<class T, class Container = std::list<T>>
typedef Container::value_type Cgu::AsyncQueue< T, Container >::value_type

Constructor & Destructor Documentation

template<class T, class Container = std::list<T>>
Cgu::AsyncQueue< T, Container >::AsyncQueue ( )
Exceptions:
std::bad_allocThe default constructor might throw std::bad_alloc if memory is exhausted and the system throws in that case.
Thread::MutexErrorThe default constructor might throw Thread::MutexError if initialization of the contained mutex fails. (It is often not worth checking for this, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.)
template<class T, class Container = std::list<T>>
Cgu::AsyncQueue< T, Container >::AsyncQueue ( AsyncQueue< T, Container > &&  rhs)
inline

As regards thread safety, the move constructor does not synchronize with respect to the initializing rvalue. This is because temporaries are only visible and accessible in the thread carrying out the move operation and synchronization for them would represent pointless overhead. In a case where a user uses std::move to force a move from a named object, and that named object's lifetime is managed by (or the object is otherwise accessed by) a different thread than the one making the move, the user must carry out her own synchronization with respect to that different thread, both to ensure that a consistent view of the the named object is obtained and because that object will be mutated by the move.

Parameters:
rhsThe AsyncQueue object to be moved.
Exceptions:
Thread::MutexErrorThe move constructor might throw Thread::MutexError if initialization of the contained mutex fails. (It is often not worth checking for this, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.) It might also throw if the queue's container type's move constructor might throw, but it should not do that unless a custom allocator is in use.
Note:
If this constructor throws Thread::MutexError, and a named object is moved using std::move, this constructor is not strongly exception safe (items in the moved queue will be lost). Fixing this efficiently requires changing the order of construction of data members of this class, which cannot be done until the next ABI break for this library as it would alter object layout. As noted above, in most cases the possibility of Thread::MutexError throwing can be ignored, but where that is not the case and strong exception safety is wanted, the user should either not employ std::move with named objects when invoking this class's constructors, or should construct an AsyncQueue object using the default constructor and then move assign to it.

Since 2.0.8

template<class T, class Container = std::list<T>>
Cgu::AsyncQueue< T, Container >::AsyncQueue ( const AsyncQueue< T, Container > &  rhs)
inline

The copy constructor is thread safe, as it locks the initializing object's mutex to obtain a consistent view of it.

Parameters:
rhsThe AsyncQueue object to be copied.
Exceptions:
std::bad_allocThe copy constructor of the queue's container type, and so this constructor, might throw std::bad_alloc if memory is exhausted and the system throws in that case. It will also throw if the copy constructor of the queue's container type throws any other exceptions, including if any copy or move constructor or copy or move assignment operator of a contained item throws.
Thread::MutexErrorThe copy constructor might throw Thread::MutexError if initialization of the contained mutex fails. (It is often not worth checking for this, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.)

Since 2.0.8

template<class T, class Container = std::list<T>>
Cgu::AsyncQueue< T, Container >::~AsyncQueue ( )
inline

The destructor does not throw unless the destructor of a contained item throws. It is thread safe (any thread may delete the AsyncQueue object).


Member Function Documentation

template<class T, class Container = std::list<T>>
template<class... Args>
void Cgu::AsyncQueue< T, Container >::emplace ( Args &&...  args)
inline

Pushes an item onto the queue by constructing it in place: that is, by passing to this method the item's constructor's arguments, rather than the item itself. This method has strong exception safety if the container is a std::list or std::deque container (the default is std::list). (Technically, for a std::deque container, emplace() only offers the same exception guarantees as does push(), namely only the basic guarantee where a copy or move of the queue item throws during the call, but the purpose of emplace is to construct in place and any reasonable implementation will not copy or move the queue item.) It is thread safe.

Parameters:
argsThe constructor arguments for the item to be pushed onto the queue.
Exceptions:
std::bad_allocThe method might throw std::bad_alloc if memory is exhausted and the system throws in that case. It might also throw if the item's constructor (including any of its constructor arguments) might throw when constructing the item.
Note:
The constructor of the item pushed onto the queue must not access any of the methods of the same queue object, or a deadlock might occur.

Since 2.0.0-rc5

template<class T, class Container = std::list<T>>
bool Cgu::AsyncQueue< T, Container >::empty ( ) const
inline
Returns:
Whether the queue is empty. It will not throw assuming that the empty() method of the container type does not throw, as it will not on any sane implementation.
Note:
This method is thread safe, but the return value may not be valid if another thread has pushed to or popped from the queue before the value returned by the method is acted on. It is provided as a utility, but may not be meaningful, depending on the intended usage.
template<class T, class Container = std::list<T>>
AsyncQueue& Cgu::AsyncQueue< T, Container >::operator= ( const AsyncQueue< T, Container > &  rhs)
inline

The assignment operator is strongly exception safe with the standard sequence containers (it uses copy and swap). It is also thread safe, as it safely locks both the assignor's and assignee's mutex to provide a thread-wise atomic assignment.

Parameters:
rhsThe assignor.
Returns:
The AsyncQueue object after assignment.
Exceptions:
std::bad_allocThe copy constructor of the queue's container type, and so this assignment operator, might throw std::bad_alloc if memory is exhausted and the system throws in that case. This assignment operator will also throw if the copy constructor of the queue's container type throws any other exceptions, including if any copy or move constructor or copy or move assignment operator of a contained item throws.
Thread::MutexErrorThe assignment operator might throw Thread::MutexError if initialization of a transitional object's contained mutex fails. (It is often not worth checking for this, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.)

Since 2.0.8

template<class T, class Container = std::list<T>>
AsyncQueue& Cgu::AsyncQueue< T, Container >::operator= ( AsyncQueue< T, Container > &&  rhs)
inline

This move assignment operator is thread safe as regards the assignee (the object moved to), but no synchronization is carried out with respect to the rvalue assignor/movant. This is because temporaries are only visible and accessible in the thread carrying out the move operation and synchronization for them would represent pointless overhead. In a case where the user uses std::move to force a move from a named object, and that named object's lifetime is managed by (or the object is otherwise accessed by) a different thread than the one making the move, the user must carry out her own synchronization with respect to that different thread, both to ensure that a consistent view of the the named object is obtained and because that object will be mutated by the move. This method invokes std::queue's move assignment operator, and therefore has the same exception safety as the standard library's implementation of that operator. It will not normally throw unless a custom allocator is used which throws on move assignment, or the destructor of a contained item throws.

Parameters:
rhsThe assignor/movant.
Returns:
The AsyncQueue object after move assignment.

Since 2.0.8

template<class T, class Container = std::list<T>>
void Cgu::AsyncQueue< T, Container >::pop ( value_type obj)
inline

Pops an item from the queue. This method has strong exception safety if the container is a std::deque or std::list container (the default is std::list), provided the destructor of a contained item does not throw. It is thread safe.

Parameters:
objA value type reference to which the item at the front of the queue will be assigned.
Exceptions:
AsyncQueuePopErrorIf the queue is empty when a pop is attempted, this method will throw AsyncQueuePopError. It might also throw if the assignment operator of the queue item might throw. In order to complete pop() operations atomically under a single lock and to retain strong exception safety, the object into which the pop()ed data is to be placed is passed as an argument by reference (this avoids a copy from a temporary object after the data has been extracted from the queue, which would occur if the item extracted were returned by value). It might also throw if the destructor of the queue item might throw (but that should never happen), or if the empty() method of the container type throws (which would not happen on any sane implementation).
template<class T, class Container = std::list<T>>
void Cgu::AsyncQueue< T, Container >::pop ( )
inline

Discards the item at the front of the queue. This method has strong exception safety if the container is a std::deque or std::list container (the default is std::list), provided the destructor of a contained item does not throw. It is thread safe.

Exceptions:
AsyncQueuePopErrorIf the queue is empty when a pop is attempted, this method will throw AsyncQueuePopError. It might also throw if the destructor of the queue item might throw (but that should never happen), or if the empty() method of the container type throws (which would not happen on any sane implementation).
template<class T, class Container = std::list<T>>
void Cgu::AsyncQueue< T, Container >::push ( const value_type obj)
inline

Pushes an item onto the queue. This method has strong exception safety if the container is a std::list or std::deque container (the default is std::list), except that if std::deque is used as the container and the copy constructor, move constructor, assignment operator or move assignment operator of the queue item throws, it only gives the basic exception guarantee (and the basic guarantee is not given by std::deque if the queue item's move constructor throws and it uses a non-default allocator which does not provide for it to be CopyInsertable). It is thread safe.

Parameters:
objThe item to be pushed onto the queue.
Exceptions:
std::bad_allocThe method might throw std::bad_alloc if memory is exhausted and the system throws in that case. It might also throw if the copy constructor, move constructor, assignment operator or move assignment operator of the queue item might throw.
template<class T, class Container = std::list<T>>
void Cgu::AsyncQueue< T, Container >::push ( value_type &&  obj)
inline

Pushes an item onto the queue. This method has strong exception safety if the container is a std::list or std::deque container (the default is std::list), except that if std::deque is used as the container and the copy constructor, move constructor, assignment operator or move assignment operator of the queue item throws, it only gives the basic exception guarantee (and the basic guarantee is not given by std::deque if the queue item's move constructor throws and it uses a non-default allocator which does not provide for it to be CopyInsertable). It is thread safe.

Parameters:
objThe item to be pushed onto the queue.
Exceptions:
std::bad_allocThe method might throw std::bad_alloc if memory is exhausted and the system throws in that case. It might also throw if the copy constructor, move constructor, assignment operator or move assignment operator of the queue item might throw.

Since 2.0.0-rc5

template<class T, class Container = std::list<T>>
size_type Cgu::AsyncQueue< T, Container >::size ( ) const
inline
Returns:
The number of items currently in the queue. It will not throw assuming that the size() method of the container type does not throw, as it will not on any sane implementation.
Note:
This method is thread safe, but the return value may not be valid if another thread has pushed to or popped from the queue before the value returned by the method is acted on. It is provided as a utility, but may not be meaningful, depending on the intended usage.

Since 2.0.8

template<class T, class Container = std::list<T>>
void Cgu::AsyncQueue< T, Container >::swap ( AsyncQueue< T, Container > &  other)
inline

Swaps the contents of 'this' and 'other'. It will not throw assuming that the swap method of the container type does not throw (which the C++11 standard requires not to happen with the standard sequence containers). It is thread safe and the swap is thread-wise atomic. A non-class function Cgu::swap(Cgu::AsyncQueue&, Cgu::AsyncQueue&) method is also provided which will call this method.

Parameters:
otherThe object to be swapped with this one.

Since 2.0.8


The documentation for this class was generated from the following file: