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) and AsyncQueue::move_pop(value_type& obj) methods provide the popped 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 pushing and popping from different threads. It is therefore useful for passing data between threads, perhaps in response to a signal being emitted from a Notifier object. Data can be pushed or pulled by move constructor/move assignment operator or by means of a std::unique_ptr object, SharedLockPtr object or an IntrusivePtr object referencing data derived from IntrusiveLockCounter.
By default the queue uses a std::list object as its container because when adding an item to the queue all allocation can take place outside the queue object's mutex. However, for types which have low overhead copy or move constructors, this 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.
template<class T, class Container = std::list<T>>
template<class... Args>
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
-
args | The constructor arguments for the item to be pushed onto the queue. |
- Exceptions
-
std::bad_alloc | The 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>>
Pops an item from the queue using the contained type's move assignment operator, if it has one, or if not using its copy assignment operator. This method is only available where the queue's container is a std::list object (which is the default), and does the same as the move_pop() method except that when popping the only thing which is done to the queue's container's internal state within the queue object's mutex is to swap some pointers: in particular, deallocation of the list node at the front of the queue occurs outside that mutex, as does assignment to this method's argument. Given that, if the queue's container is a list, any new node is also constructed outside the mutex when pushing or emplacing an item onto the queue, this minimizes contention between threads: it gets as close to lock-free performance as it is possible to get with the standard containers.
However this minimizing of contention comes at a cost, which is that if the contained item's move assignment operator (or if it has none, its copy assignment operator) throws, then only the basic exception guarantee is offered (hence the name of this method). This means that although the AsyncQueue object would be left in a valid state in the event of such throwing, the item at the front of the queue would be lost. As in the case of the pop() and move_pop() methods, in addition only the basic exception guarantee is offered if the destructor of the contained item throws. Only use this method if the queue's container is a std::list object, and if either it is known that the contained item's move assignment operator (or if it has none, its copy assignment operator) does not throw, or the use case does not require strong exception safety. This method is thread safe.
If this method is called for an AsyncQueue object whose container is not a std::list object, it will hand off to the move_pop() method, which is separately documented.
- Parameters
-
obj | A value type reference to which the item at the front of the queue will be move assigned. |
- Exceptions
-
AsyncQueuePopError | If the queue is empty when a pop is attempted, this method will throw AsyncQueuePopError. It might also throw if the move assignment operator of the queue item might throw or it has no move assignment operator and its copy assignment operator throws (in which case only the basic exception guarantee is offered). It might also throw if the destructor of the queue item might throw (but that should never happen), if the empty() method of the container type throws (which would not happen on any sane implementation) or if the constructor of the implementation's list allocator throws (which would be highly unusual). In the event of any of the last two throwing, the strong exception guarantee is offered. |
Since 2.0.26
template<class T, class Container = std::list<T>>
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
-
- Returns
- The AsyncQueue object after move assignment.
Since 2.0.8
template<class T, class Container = std::list<T>>
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, copy 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
-
obj | The item to be pushed onto the queue. |
- Exceptions
-
std::bad_alloc | The 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>>
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, copy 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
-
obj | The item to be pushed onto the queue. |
- Exceptions
-
std::bad_alloc | The 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