c++-gtk-utils
async_queue.h
Go to the documentation of this file.
00001 /* Copyright (C) 2006 to 2012 Chris Vine
00002 
00003 The library comprised in this file or of which this file is part is
00004 distributed by Chris Vine under the GNU Lesser General Public
00005 License as follows:
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public License
00009    as published by the Free Software Foundation; either version 2.1 of
00010    the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful, but
00013    WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License, version 2.1, for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License, version 2.1, along with this library (see the file LGPL.TXT
00019    which came with this source code package in the c++-gtk-utils
00020    sub-directory); if not, write to the Free Software Foundation, Inc.,
00021    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00022 
00023 However, it is not intended that the object code of a program whose
00024 source code instantiates a template from this file or uses macros or
00025 inline functions (of any length) should by reason only of that
00026 instantiation or use be subject to the restrictions of use in the GNU
00027 Lesser General Public License.  With that in mind, the words "and
00028 macros, inline functions and instantiations of templates (of any
00029 length)" shall be treated as substituted for the words "and small
00030 macros and small inline functions (ten lines or less in length)" in
00031 the fourth paragraph of section 5 of that licence.  This does not
00032 affect any other reason why object code may be subject to the
00033 restrictions in that licence (nor for the avoidance of doubt does it
00034 affect the application of section 2 of that licence to modifications
00035 of the source code in this file).
00036 
00037 */
00038 
00039 /**
00040  * @file async_queue.h
00041  * @brief This file provides thread-safe asynchronous queue classes.
00042  *
00043  * AsyncQueue is a class which provides some of the functionality of a
00044  * std::queue object (but note that the AsyncQueue::pop(value_type&
00045  * obj) method provides the pop()ed element by reference - see the
00046  * comments on that method for the reason), except that it has mutex
00047  * locking of the data container so as to permit push()ing and
00048  * pop()ing from different threads.  It is therefore useful for
00049  * passing data between threads, perhaps in response to a signal being
00050  * emitted from a Notifier object.  Passing the data by means of a
00051  * SharedLockPtr object, or an IntrusivePtr object referencing data
00052  * derived from IntrusiveLockCounter, would be ideal.
00053  *
00054  * AsyncQueueDispatch is a class which has a blocking pop() method,
00055  * which allows it to be waited on by a dedicated event/message
00056  * dispatching thread for incoming work (represented by the data
00057  * pushed onto the queue).  In the same way, it can be used to
00058  * implement thread pools, by having threads in the pool waiting on
00059  * the queue.
00060  *
00061  * By default the queues use a std::list object as their container
00062  * because in the kind of use mentioned above they are unlikely to
00063  * hold many objects but they can be changed to, say, a std::deque
00064  * object by specifying it as the second template parameter.
00065  */
00066 
00067 #ifndef CGU_ASYNC_QUEUE_H
00068 #define CGU_ASYNC_QUEUE_H
00069 
00070 #include <queue>
00071 #include <list>
00072 #include <exception>
00073 #include <utility>    // for std::move and std::forward
00074 #include <time.h>
00075 
00076 #include <c++-gtk-utils/mutex.h>
00077 #include <c++-gtk-utils/thread.h>
00078 #include <c++-gtk-utils/cgu_config.h>
00079 
00080 namespace Cgu {
00081 
00082 /**
00083  * @class AsyncQueuePopError async_queue.h c++-gtk-utils/async_queue.h
00084  * @brief An exception thrown if calling pop() on a AsyncQueue or
00085  * AsyncQueueDispatch object fails because the queue is empty.
00086  * @sa AsyncQueue AsyncQueueDispatch
00087  */
00088 
00089 struct AsyncQueuePopError: public std::exception {
00090   virtual const char* what() const throw() {return "AsyncQueuePopError: popping from empty AsyncQueue object\n";}
00091 };
00092 
00093 
00094 /**
00095  * @class AsyncQueue async_queue.h c++-gtk-utils/async_queue.h
00096  * @brief A thread-safe asynchronous queue.
00097  * @sa AsyncQueueDispatch
00098  *
00099  * AsyncQueue is a class which provides some of the functionality of a
00100  * std::queue object (but note that the AsyncQueue::pop(value_type&
00101  * obj) method provides the pop()ed element by reference - see the
00102  * comments on that method for the reason), except that it has mutex
00103  * locking of the data container so as to permit push()ing and
00104  * pop()ing from different threads.  It is therefore useful for
00105  * passing data between threads, perhaps in response to a signal being
00106  * emitted from a Notifier object.  Passing the data by means of a
00107  * SharedLockPtr object, or an IntrusivePtr object referencing data
00108  * derived from IntrusiveLockCounter, would be ideal.
00109  *
00110  * By default the queue uses a std::list object as its container
00111  * because in the kind of use mentioned above it is unlikely to hold
00112  * many objects but it can be changed to, say, a std::deque object by
00113  * specifying it as the second template parameter.
00114  *
00115  * If the library is installed using the
00116  * --with-glib-memory-slices-compat or
00117  * --with-glib-memory-slices-no-compat configuration options, any
00118  * AsyncQueue objects constructed on free store will be constructed in
00119  * glib memory slices.  This does not affect the queue container
00120  * itself: to change the allocator of the C++ container, a custom
00121  * allocator type can be provided when the AsyncQueue object is
00122  * instantiated offering the standard allocator interface.  If glib
00123  * memory slices are not used or no AsyncQueue objects are constructed
00124  * on free store, it is not necessary to call g_thread_init() before
00125  * manipulating or using an AsyncQueue object in multiple threads, but
00126  * prior to glib version 2.32 glib itself (and thus glib memory
00127  * slices) are not thread safe unless that function has been called.
00128  */
00129 
00130 template <class T, class Container = std::list<T> > class AsyncQueue {
00131 public:
00132   typedef typename Container::value_type value_type;
00133   typedef typename Container::size_type size_type;
00134   typedef Container container_type;
00135 private:
00136   std::queue<T, Container> q;
00137   mutable Thread::Mutex mutex;
00138 
00139 public:
00140 /**
00141  * Pushes an item onto the queue.  This method has strong exception
00142  * safety if the container is a std::list or std::deque container (the
00143  * default is std::list), except that if std::deque is used as the
00144  * container and the copy constructor, move constructor, assignment
00145  * operator or move assignment operator of the queue item throws, it
00146  * only gives the basic exception guarantee (and the basic guarantee
00147  * is not given by std::deque if the queue item's move constructor
00148  * throws and it uses a non-default allocator which does not provide
00149  * for it to be CopyInsertable).  It is thread safe.
00150  * @param obj The item to be pushed onto the queue.
00151  * @exception std::bad_alloc The method might throw std::bad_alloc if
00152  * memory is exhausted and the system throws in that case.  It might
00153  * also throw if the copy constructor, move constructor, assignment
00154  * operator or move assignment operator of the queue item might throw.
00155  */
00156   void push(const value_type& obj) {
00157     Thread::Mutex::Lock lock{mutex};
00158     q.push(obj);
00159   }
00160 
00161 /**
00162  * Pushes an item onto the queue.  This method has strong exception
00163  * safety if the container is a std::list or std::deque container (the
00164  * default is std::list), except that if std::deque is used as the
00165  * container and the copy constructor, move constructor, assignment
00166  * operator or move assignment operator of the queue item throws, it
00167  * only gives the basic exception guarantee (and the basic guarantee
00168  * is not given by std::deque if the queue item's move constructor
00169  * throws and it uses a non-default allocator which does not provide
00170  * for it to be CopyInsertable).  It is thread safe.
00171  * @param obj The item to be pushed onto the queue.
00172  * @exception std::bad_alloc The method might throw std::bad_alloc if
00173  * memory is exhausted and the system throws in that case.  It might
00174  * also throw if the copy constructor, move constructor, assignment
00175  * operator or move assignment operator of the queue item might throw.
00176  *
00177  * Since 2.0.0-rc5
00178  */
00179   void push(value_type&& obj) {
00180     Thread::Mutex::Lock lock{mutex};
00181     q.push(std::move(obj));
00182   }
00183 
00184 /**
00185  * Pushes an item onto the queue by constructing it in place: that is,
00186  * by passing to this method the item's constructor's arguments,
00187  * rather than the item itself.  This method has strong exception
00188  * safety if the container is a std::list or std::deque container (the
00189  * default is std::list).  (Technically, for a std::deque container,
00190  * emplace() only offers the same exception guarantees as does push(),
00191  * namely only the basic guarantee where a copy or move of the queue
00192  * item throws during the call, but the purpose of emplace is to
00193  * construct in place and any reasonable implementation will not copy
00194  * or move the queue item.)  It is thread safe.
00195  * @param args The constructor arguments for the item to be pushed
00196  * onto the queue.
00197  * @exception std::bad_alloc The method might throw std::bad_alloc if
00198  * memory is exhausted and the system throws in that case.  It might
00199  * also throw if the item's constructor (including any of its
00200  * constructor arguments) might throw when constructing the item.
00201  * @note The constructor of the item pushed onto the queue must not
00202  * access any of the methods of the same queue object, or a deadlock
00203  * might occur.
00204  *
00205  * Since 2.0.0-rc5
00206  */
00207   template<class... Args>
00208   void emplace(Args&&... args) {
00209     Thread::Mutex::Lock lock{mutex};
00210     q.emplace(std::forward<Args>(args)...);
00211   }
00212 
00213 /**
00214  * Pops an item from the queue.  This method has strong exception
00215  * safety if the container is a std::deque or std::list container (the
00216  * default is std::list), provided the destructor of a contained item
00217  * does not throw.  It is thread safe.
00218  * @param obj A value type reference to which the item at the front of
00219  * the queue will be assigned.
00220  * @exception AsyncQueuePopError If the queue is empty when a pop is
00221  * attempted, this method will throw AsyncQueuePopError.  It might
00222  * also throw if the assignment operator of the queue item might
00223  * throw.  In order to complete pop() operations atomically under a
00224  * single lock and to retain strong exception safety, the object into
00225  * which the pop()ed data is to be placed is passed as an argument by
00226  * reference (this avoids a copy from a temporary object after the
00227  * data has been extracted from the queue, which would occur if the
00228  * item extracted were returned by value).  It might also throw if the
00229  * destructor of the queue item might throw (but that should never
00230  * happen), or if the empty() method of the container type throws
00231  * (which would not happen on any sane implementation).
00232  */
00233   void pop(value_type& obj) {
00234     Thread::Mutex::Lock lock{mutex};
00235     if (q.empty()) throw AsyncQueuePopError();
00236     obj = q.front();
00237     q.pop();
00238   }
00239 
00240 /**
00241  * Discards the item at the front of the queue.  This method has
00242  * strong exception safety if the container is a std::deque or
00243  * std::list container (the default is std::list), provided the
00244  * destructor of a contained item does not throw.  It is thread safe.
00245  * @exception AsyncQueuePopError If the queue is empty when a pop is
00246  * attempted, this method will throw AsyncQueuePopError.  It might
00247  * also throw if the destructor of the queue item might throw (but
00248  * that should never happen), or if the empty() method of the
00249  * container type throws (which would not happen on any sane
00250  * implementation).
00251  */
00252   void pop() {
00253     Thread::Mutex::Lock lock{mutex};
00254     if (q.empty()) throw AsyncQueuePopError();
00255     q.pop();
00256   }
00257 
00258 /**
00259  * @return Whether the queue is empty.  It will not throw assuming
00260  * that the empty() method of the container type does not throw, as it
00261  * will not on any sane implementation.
00262  * @note This method is thread safe, but the return value may not be
00263  * valid if another thread has pushed to or popped from the queue
00264  * before the value returned by the method is acted on.  It is
00265  * provided as a utility, but may not be meaningful, depending on the
00266  * intended usage.
00267  */
00268   bool empty() const {
00269     Thread::Mutex::Lock lock{mutex};
00270     return q.empty();
00271   }
00272 
00273 /**
00274  * @exception std::bad_alloc The constructor might throw
00275  * std::bad_alloc if memory is exhausted and the system throws in that
00276  * case.
00277  * @exception Thread::MutexError The constructor might throw
00278  * Thread::MutexError if initialisation of the contained mutex fails.
00279  * (It is often not worth checking for this, as it means either memory
00280  * is exhausted or pthread has run out of other resources to create
00281  * new mutexes.)
00282 */
00283   AsyncQueue() = default;
00284 
00285 // AsyncQueue objects cannot be copied - they are mainly
00286 // intended to pass data between two known threads
00287 /**
00288  * This class cannot be copied.  The copy constructor is deleted.
00289  */
00290   AsyncQueue(const AsyncQueue&) = delete;
00291 
00292 /**
00293  * This class cannot be copied.  The assignment operator is deleted.
00294  */
00295   AsyncQueue& operator=(const AsyncQueue&) = delete;
00296 
00297 /**
00298  * The destructor does not throw unless the destructor of a contained
00299  * item throws.  It is thread safe (any thread may delete the
00300  * AsyncQueue object).
00301  */
00302   ~AsyncQueue() {
00303     // lock and unlock the mutex in the destructor so that we have an
00304     // acquire operation to ensure that when the std::queue object is
00305     // destroyed memory is synchronised, so any thread may destroy the
00306     // AsyncQueue object
00307     Thread::Mutex::Lock lock{mutex};
00308   }
00309 
00310 /* Only has effect if --with-glib-memory-slices-compat or
00311  * --with-glib-memory-slices-no-compat option picked */
00312   CGU_GLIB_MEMORY_SLICES_FUNCS
00313 };
00314 
00315 /**
00316  * @class AsyncQueueDispatch async_queue.h c++-gtk-utils/async_queue.h
00317  * @brief A thread-safe asynchronous queue with a blocking pop()
00318  * method.
00319  * @sa AsyncQueue
00320  *
00321  * AsyncQueueDispatch is similar to the AsyncQueue class, except that
00322  * it has a blocking pop_dispatch() method, which allows it to be
00323  * waited on by a dedicated event/message dispatching thread for
00324  * incoming work (represented by the data pushed onto the queue).  In
00325  * the same way, it can be used to implement thread pools, by having
00326  * threads in the pool waiting on the queue.
00327  *
00328  * By default the queue uses a std::list object as its container
00329  * because in the kind of use mentioned above it is unlikely to hold
00330  * many objects but it can be changed to, say, a std::deque object by
00331  * specifying it as the second template parameter.
00332  *
00333  * If the library is installed using the
00334  * --with-glib-memory-slices-compat or
00335  * --with-glib-memory-slices-no-compat configuration options, any
00336  * AsyncQueueDispatch objects constructed on free store will be
00337  * constructed in glib memory slices.  This does not affect the queue
00338  * container itself: to change the allocator of the C++ container, a
00339  * custom allocator type can be provided when the AsyncQueueDispatch
00340  * object is instantiated offering the standard allocator interface.
00341  * If glib memory slices are not used or no AsyncQueueDispatch objects
00342  * are constructed on free store, it is not necessary to call
00343  * g_thread_init() before manipulating or using an AsyncQueueDispatch
00344  * object in multiple threads, but prior to glib version 2.32 glib
00345  * itself (and thus glib memory slices) are not thread safe unless
00346  * that function has been called.
00347  */
00348 
00349 template <class T, class Container = std::list<T> > class AsyncQueueDispatch {
00350 public:
00351   typedef typename Container::value_type value_type;
00352   typedef typename Container::size_type size_type;
00353   typedef Container container_type;
00354 private:
00355   std::queue<T, Container> q;
00356   mutable Thread::Mutex mutex;
00357   Thread::Cond cond;
00358 
00359 public:
00360 /**
00361  * Pushes an item onto the queue.  This method has strong exception
00362  * safety if the container is a std::list or std::deque container (the
00363  * default is std::list), except that if std::deque is used as the
00364  * container and the copy constructor, move constructor, assignment
00365  * operator or move assignment operator of the queue item throws, it
00366  * only gives the basic exception guarantee (and the basic guarantee
00367  * is not given by std::deque if the queue item's move constructor
00368  * throws and it uses a non-default allocator which does not provide
00369  * for it to be CopyInsertable).  It is thread safe.
00370  * @param obj The item to be pushed onto the queue.
00371  * @exception std::bad_alloc The method might throw std::bad_alloc if
00372  * memory is exhausted and the system throws in that case.  It might
00373  * also throw if the copy constructor, move constructor, assignment
00374  * operator or move assignment operator of the queue item might throw.
00375  */
00376   void push(const value_type& obj) {
00377     Thread::Mutex::Lock lock{mutex};
00378     q.push(obj);
00379     cond.signal();
00380   }
00381 
00382 /**
00383  * Pushes an item onto the queue.  This method has strong exception
00384  * safety if the container is a std::list or std::deque container (the
00385  * default is std::list), except that if std::deque is used as the
00386  * container and the copy constructor, move constructor, assignment
00387  * operator or move assignment operator of the queue item throws, it
00388  * only gives the basic exception guarantee (and the basic guarantee
00389  * is not given by std::deque if the queue item's move constructor
00390  * throws and it uses a non-default allocator which does not provide
00391  * for it to be CopyInsertable).  It is thread safe.
00392  * @param obj The item to be pushed onto the queue.
00393  * @exception std::bad_alloc The method might throw std::bad_alloc if
00394  * memory is exhausted and the system throws in that case.  It might
00395  * also throw if the copy constructor, move constructor, assignment
00396  * operator or move assignment operator of the queue item might throw.
00397  *
00398  * Since 2.0.0-rc5
00399  */
00400   void push(value_type&& obj) {
00401     Thread::Mutex::Lock lock{mutex};
00402     q.push(std::move(obj));
00403     cond.signal();
00404   }
00405 
00406 /**
00407  * Pushes an item onto the queue by constructing it in place: that is,
00408  * by passing to this method the item's constructor's arguments,
00409  * rather than the item itself.  This method has strong exception
00410  * safety if the container is a std::list or std::deque container (the
00411  * default is std::list).  (Technically, for a std::deque container,
00412  * emplace() only offers the same exception guarantees as does push(),
00413  * namely only the basic guarantee where a copy or move of the queue
00414  * item throws during the call, but the purpose of emplace is to
00415  * construct in place and any reasonable implementation will not copy
00416  * or move the queue item.)  It is thread safe.
00417  * @param args The constructor arguments for the item to be pushed
00418  * onto the queue.
00419  * @exception std::bad_alloc The method might throw std::bad_alloc if
00420  * memory is exhausted and the system throws in that case.  It might
00421  * also throw if the item's constructor (including any of its
00422  * constructor arguments) might throw when constructing the item.
00423  * @note The constructor of the item pushed onto the queue must not
00424  * access any of the methods of the same queue object, or a deadlock
00425  * might occur.
00426  *
00427  * Since 2.0.0-rc5
00428  */
00429   template<class... Args>
00430   void emplace(Args&&... args) {
00431     Thread::Mutex::Lock lock{mutex};
00432     q.emplace(std::forward<Args>(args)...);
00433     cond.signal();
00434   }
00435 
00436 /**
00437  * Pops an item from the queue.  This method has strong exception
00438  * safety if the container is a std::deque or std::list container (the
00439  * default is std::list), provided the destructor of a contained item
00440  * does not throw.  It is thread safe.
00441  * @param obj A value type reference to which the item at the front of
00442  * the queue will be assigned.
00443  * @exception AsyncQueuePopError If the queue is empty when a pop is
00444  * attempted, this method will throw AsyncQueuePopError.  It might
00445  * also throw if the assignment operator of the queue item might
00446  * throw.  In order to complete pop() operations atomically under a
00447  * single lock and to retain strong exception safety, the object into
00448  * which the pop()ed data is to be placed is passed as an argument by
00449  * reference (this avoids a copy from a temporary object after the
00450  * data has been extracted from the queue, which would occur if the
00451  * item extracted were returned by value).  It might also throw if the
00452  * destructor of the queue item might throw (but that should never
00453  * happen), or if the empty() method of the container type throws
00454  * (which would not happen on any sane implementation).
00455  */
00456   void pop(value_type& obj) {
00457     Thread::Mutex::Lock lock{mutex};
00458     if (q.empty()) throw AsyncQueuePopError();
00459     obj = q.front();
00460     q.pop();
00461   }
00462 
00463 /**
00464  * Pops an item from the queue.  If the queue is empty, it will block
00465  * until an item becomes available.  If it blocks, the wait comprises
00466  * a cancellation point.  This method is cancellation safe if the
00467  * stack unwinds on cancellation, as cancellation is blocked while the
00468  * queue is being operated on after coming out of a wait.  This method
00469  * has strong exception safety if the container is a std::deque or
00470  * std::list container (the default is std::list), provided the
00471  * destructor of a contained item does not throw.  It is thread safe.
00472  * @param obj A value type reference to which the item at the front of
00473  * the queue will be assigned.  This method might throw if the
00474  * assignment operator of the queue item might throw.  In order to
00475  * complete pop() operations atomically under a single lock and to
00476  * retain strong exception safety, the object into which the pop()ed
00477  * data is to be placed is passed as an argument by reference (this
00478  * avoids a copy from a temporary object after the data has been
00479  * extracted from the queue, which would occur if the item extracted
00480  * were returned by value).  It might also throw if the destructor of
00481  * the queue item might throw (but that should never happen), or if
00482  * the empty() method of the container type throws (which would not
00483  * happen on any sane implementation).
00484  */
00485   void pop_dispatch(value_type& obj) {
00486     Thread::Mutex::Lock lock{mutex};
00487     while (q.empty()) cond.wait(mutex);
00488     Thread::CancelBlock b;
00489     obj = q.front();
00490     q.pop();
00491   }    
00492 
00493 /**
00494  * Pops an item from the queue.  If the queue is empty, it will block
00495  * until an item becomes available or until the timeout expires.  If
00496  * it blocks, the wait comprises a cancellation point.  This method is
00497  * cancellation safe if the stack unwinds on cancellation, as
00498  * cancellation is blocked while the queue is being operated on after
00499  * coming out of a wait.  This method has strong exception safety if
00500  * the container is a std::deque or std::list container (the default
00501  * is std::list), provided the destructor of a contained item does not
00502  * throw.  It is thread safe.
00503  * @param obj A value type reference to which the item at the front of
00504  * the queue will be assigned.  This method might throw if the
00505  * assignment operator of the queue item might throw.  In order to
00506  * complete pop() operations atomically under a single lock and to
00507  * retain strong exception safety, the object into which the pop()ed
00508  * data is to be placed is passed as an argument by reference (this
00509  * avoids a copy from a temporary object after the data has been
00510  * extracted from the queue, which would occur if the item extracted
00511  * were returned by value).  It might also throw if the destructor of
00512  * the queue item might throw (but that should never happen), or if
00513  * the empty() method of the container type throws (which would not
00514  * happen on any sane implementation).
00515  * @param millisec The timeout interval, in milliseconds.
00516  * @return If the timeout expires without an item becoming available,
00517  * the method will return true.  If an item from the queue is
00518  * extracted, it returns false.
00519  */
00520   bool pop_timed_dispatch(value_type& obj, unsigned int millisec) {
00521     timespec ts;
00522     Thread::Cond::get_abs_time(ts, millisec);
00523     Thread::Mutex::Lock lock{mutex};
00524     while (q.empty()) {
00525       if (cond.timed_wait(mutex, ts)) return true;
00526     }
00527     Thread::CancelBlock b;
00528     obj = q.front();
00529     q.pop();
00530     return false;
00531   }
00532 
00533 /**
00534  * Discards the item at the front of the queue.  This method has
00535  * strong exception safety if the container is a std::deque or
00536  * std::list container (the default is std::list), provided the
00537  * destructor of a contained item does not throw.  It is thread safe.
00538  * @exception AsyncQueuePopError If the queue is empty when a pop is
00539  * attempted, this method will throw AsyncQueuePopError.  It might
00540  * also throw if the destructor of the queue item might throw (but
00541  * that should never happen), or if the empty() method of the
00542  * container type throws (which would not happen on any sane
00543  * implementation).
00544  */
00545   void pop() {
00546     Thread::Mutex::Lock lock{mutex};
00547     if (q.empty()) throw AsyncQueuePopError();
00548     q.pop();
00549   }
00550 
00551 /**
00552  * @return Whether the queue is empty.  It will not throw assuming
00553  * that the empty() method of the container type does not throw, as it
00554  * will not on any sane implementation.
00555  * @note This method is thread safe, but the return value may not be
00556  * valid if another thread has pushed to or popped from the queue
00557  * before the value returned by the method is acted on.  It is
00558  * provided as a utility, but may not be meaningful, depending on the
00559  * intended usage.
00560  */
00561   bool empty() const {
00562     Thread::Mutex::Lock lock{mutex};
00563     return q.empty();
00564   }
00565 
00566 /**
00567  * @exception std::bad_alloc The constructor might throw this
00568  * exception if memory is exhausted and the system throws in that
00569  * case.
00570  * @exception Thread::MutexError The constructor might throw this
00571  * exception if initialisation of the contained mutex fails.  (It is
00572  * often not worth checking for this, as it means either memory is
00573  * exhausted or pthread has run out of other resources to create new
00574  * mutexes.)
00575  * @exception Thread::CondError The constructor might throw this
00576  * exception if initialisation of the contained condition variable
00577  * fails.  (It is often not worth checking for this, as it means
00578  * either memory is exhausted or pthread has run out of other
00579  * resources to create new condition variables.)
00580  */
00581   AsyncQueueDispatch() = default;
00582 
00583   // AsyncQueueDispatch objects cannot be copied - they are mainly
00584   // intended to pass data between two known threads
00585 /**
00586  * This class cannot be copied.  The copy constructor is deleted.
00587  */
00588   AsyncQueueDispatch(const AsyncQueueDispatch&) = delete;
00589 
00590 /**
00591  * This class cannot be copied.  The assignment operator is deleted.
00592  */
00593   AsyncQueueDispatch& operator=(const AsyncQueueDispatch&) = delete;
00594 
00595 /**
00596  * The destructor does not throw unless the destructor of a contained
00597  * item throws.  It is thread safe (any thread may delete the
00598  * AsyncQueueDispatch object).
00599  */
00600   ~AsyncQueueDispatch() {
00601     // lock and unlock the mutex in the destructor so that we have an
00602     // acquire operation to ensure that when the std::queue object is
00603     // destroyed memory is synchronised, so any thread may destroy the
00604     // AsyncQueueDispatch object
00605     Thread::Mutex::Lock lock{mutex};
00606   }
00607 
00608 /* Only has effect if --with-glib-memory-slices-compat or
00609  * --with-glib-memory-slices-no-compat option picked */
00610   CGU_GLIB_MEMORY_SLICES_FUNCS
00611 };
00612 
00613 } // namespace Cgu
00614 
00615 #endif