c++-gtk-utils
async_queue.h
Go to the documentation of this file.
00001 /* Copyright (C) 2006 to 2011 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    59 Temple Place - Suite 330, Boston, MA, 02111-1307, 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.
00123  */
00124 
00125 template <class T, class Container = std::list<T> > class AsyncQueue {
00126 public:
00127   typedef typename Container::value_type value_type;
00128   typedef typename Container::size_type size_type;
00129   typedef Container container_type;
00130 private:
00131   std::queue<T, Container> q;
00132   mutable Thread::Mutex mutex;
00133 
00134 public:
00135 /**
00136  * Pushes an item onto the queue.  This method has strong exception
00137  * safety if the container is a std::list or std::deque container (the
00138  * default is std::list), except that if std::deque is used as the
00139  * container and the copy constructor, move constructor, assignment
00140  * operator or move assignment operator of the queue item throws, it
00141  * only gives the basic exception guarantee (and the basic guarantee
00142  * is not given by std::deque if the queue item's move constructor
00143  * throws and it uses a non-default allocator which does not provide
00144  * for it to be CopyInsertable).  It is thread safe.
00145  * @param obj The item to be pushed onto the queue.
00146  * @exception std::bad_alloc The method might throw std::bad_alloc if
00147  * memory is exhausted and the system throws in that case.  It might
00148  * also throw if the copy constructor, move constructor, assignment
00149  * operator or move assignment operator of the queue item might throw.
00150  */
00151   void push(const value_type& obj) {
00152     Thread::Mutex::Lock lock{mutex};
00153     q.push(obj);
00154   }
00155 
00156 /**
00157  * Pushes an item onto the queue.  This method has strong exception
00158  * safety if the container is a std::list or std::deque container (the
00159  * default is std::list), except that if std::deque is used as the
00160  * container and the copy constructor, move constructor, assignment
00161  * operator or move assignment operator of the queue item throws, it
00162  * only gives the basic exception guarantee (and the basic guarantee
00163  * is not given by std::deque if the queue item's move constructor
00164  * throws and it uses a non-default allocator which does not provide
00165  * for it to be CopyInsertable).  It is thread safe.
00166  * @param obj The item to be pushed onto the queue.
00167  * @exception std::bad_alloc The method might throw std::bad_alloc if
00168  * memory is exhausted and the system throws in that case.  It might
00169  * also throw if the copy constructor, move constructor, assignment
00170  * operator or move assignment operator of the queue item might throw.
00171  *
00172  * Since 2.0.0-rc5
00173  */
00174   void push(value_type&& obj) {
00175     Thread::Mutex::Lock lock{mutex};
00176     q.push(std::move(obj));
00177   }
00178 
00179 /**
00180  * Pushes an item onto the queue by constructing it in place: that is,
00181  * by passing to this method the item's constructor's arguments,
00182  * rather than the item itself.  This method has strong exception
00183  * safety if the container is a std::list or std::deque container (the
00184  * default is std::list).  (Technically, for a std::deque container,
00185  * emplace() only offers the same exception guarantees as does push(),
00186  * namely only the basic guarantee where a copy or move of the queue
00187  * item throws during the call, but the purpose of emplace is to
00188  * construct in place and any reasonable implementation will not copy
00189  * or move the queue item.)  It is thread safe.
00190  * @param args The constructor arguments for the item to be pushed
00191  * onto the queue.
00192  * @exception std::bad_alloc The method might throw std::bad_alloc if
00193  * memory is exhausted and the system throws in that case.  It might
00194  * also throw if the item's constructor (including any of its
00195  * constructor arguments) might throw when constructing the item.
00196  * @note The constructor of the item pushed onto the queue must not
00197  * access any of the methods of the same queue object, or a deadlock
00198  * might occur.
00199  *
00200  * Since 2.0.0-rc5
00201  */
00202   template<class... Args>
00203   void emplace(Args&&... args) {
00204     Thread::Mutex::Lock lock{mutex};
00205     q.emplace(std::forward<Args>(args)...);
00206   }
00207 
00208 /**
00209  * Pops an item from the queue.  This method has strong exception
00210  * safety if the container is a std::deque or std::list container (the
00211  * default is std::list), provided the destructor of a contained item
00212  * does not throw.  It is thread safe.
00213  * @param obj A value type reference to which the item at the front of
00214  * the queue will be assigned.
00215  * @exception AsyncQueuePopError If the queue is empty when a pop is
00216  * attempted, this method will throw AsyncQueuePopError.  It might
00217  * also throw if the assignment operator of the queue item might
00218  * throw.  In order to complete pop() operations atomically under a
00219  * single lock and to retain strong exception safety, the object into
00220  * which the pop()ed data is to be placed is passed as an argument by
00221  * reference (this avoids a copy from a temporary object after the
00222  * data has been extracted from the queue, which would occur if the
00223  * item extracted were returned by value).  It might also throw if the
00224  * destructor of the queue item might throw (but that should never
00225  * happen), or if the empty() method of the container type throws
00226  * (which would not happen on any sane implementation).
00227  */
00228   void pop(value_type& obj) {
00229     Thread::Mutex::Lock lock{mutex};
00230     if (q.empty()) throw AsyncQueuePopError();
00231     obj = q.front();
00232     q.pop();
00233   }
00234 
00235 /**
00236  * Discards the item at the front of the queue.  This method has
00237  * strong exception safety if the container is a std::deque or
00238  * std::list container (the default is std::list), provided the
00239  * destructor of a contained item does not throw.  It is thread safe.
00240  * @exception AsyncQueuePopError If the queue is empty when a pop is
00241  * attempted, this method will throw AsyncQueuePopError.  It might
00242  * also throw if the destructor of the queue item might throw (but
00243  * that should never happen), or if the empty() method of the
00244  * container type throws (which would not happen on any sane
00245  * implementation).
00246  */
00247   void pop() {
00248     Thread::Mutex::Lock lock{mutex};
00249     if (q.empty()) throw AsyncQueuePopError();
00250     q.pop();
00251   }
00252 
00253 /**
00254  * @return Whether the queue is empty.  It will not throw assuming
00255  * that the empty() method of the container type does not throw, as it
00256  * will not on any sane implementation.
00257  * @note This method is thread safe, but the return value may not be
00258  * valid if another thread has pushed to or popped from the queue
00259  * before the value returned by the method is acted on.  It is
00260  * provided as a utility, but may not be meaningful, depending on the
00261  * intended usage.
00262  */
00263   bool empty() const {
00264     Thread::Mutex::Lock lock{mutex};
00265     return q.empty();
00266   }
00267 
00268 /**
00269  * @exception std::bad_alloc The constructor might throw
00270  * std::bad_alloc if memory is exhausted and the system throws in that
00271  * case.
00272  * @exception Thread::MutexError The constructor might throw
00273  * Thread::MutexError if initialisation of the contained mutex fails.
00274  * (It is often not worth checking for this, as it means either memory
00275  * is exhausted or pthread has run out of other resources to create
00276  * new mutexes.)
00277 */
00278   AsyncQueue() = default;
00279 
00280 // AsyncQueue objects cannot be copied - they are mainly
00281 // intended to pass data between two known threads
00282 /**
00283  * This class cannot be copied.  The copy constructor is deleted.
00284  */
00285   AsyncQueue(const AsyncQueue&) = delete;
00286 
00287 /**
00288  * This class cannot be copied.  The assignment operator is deleted.
00289  */
00290   AsyncQueue& operator=(const AsyncQueue&) = delete;
00291 
00292 /**
00293  * The destructor does not throw unless the destructor of a contained
00294  * item throws.  It is thread safe (any thread may delete the
00295  * AsyncQueue object).
00296  */
00297   ~AsyncQueue() {
00298     // lock and unlock the mutex in the destructor so that we have an
00299     // acquire operation to ensure that when the std::queue object is
00300     // destroyed memory is synchronised, so any thread may destroy the
00301     // AsyncQueue object
00302     Thread::Mutex::Lock lock{mutex};
00303   }
00304 
00305 /* Only has effect if --with-glib-memory-slices-compat or
00306  * --with-glib-memory-slices-no-compat option picked */
00307   CGU_GLIB_MEMORY_SLICES_FUNCS
00308 };
00309 
00310 /**
00311  * @class AsyncQueueDispatch async_queue.h c++-gtk-utils/async_queue.h
00312  * @brief A thread-safe asynchronous queue with a blocking pop()
00313  * method.
00314  * @sa AsyncQueue
00315  *
00316  * AsyncQueueDispatch is similar to the AsyncQueue class, except that
00317  * it has a blocking pop_dispatch() method, which allows it to be
00318  * waited on by a dedicated event/message dispatching thread for
00319  * incoming work (represented by the data pushed onto the queue).  In
00320  * the same way, it can be used to implement thread pools, by having
00321  * threads in the pool waiting on the queue.
00322  *
00323  * By default the queue uses a std::list object as its container
00324  * because in the kind of use mentioned above it is unlikely to hold
00325  * many objects but it can be changed to, say, a std::deque object by
00326  * specifying it as the second template parameter.
00327  *
00328  * If the library is installed using the
00329  * --with-glib-memory-slices-compat or
00330  * --with-glib-memory-slices-no-compat configuration options, any
00331  * AsyncQueueDispatch objects constructed on free store will be
00332  * constructed in glib memory slices.  This does not affect the queue
00333  * container itself: to change the allocator of the C++ container, a
00334  * custom allocator type can be provided when the AsyncQueueDispatch
00335  * object is instantiated offering the standard allocator interface.
00336  */
00337 
00338 template <class T, class Container = std::list<T> > class AsyncQueueDispatch {
00339 public:
00340   typedef typename Container::value_type value_type;
00341   typedef typename Container::size_type size_type;
00342   typedef Container container_type;
00343 private:
00344   std::queue<T, Container> q;
00345   mutable Thread::Mutex mutex;
00346   Thread::Cond cond;
00347 
00348 public:
00349 /**
00350  * Pushes an item onto the queue.  This method has strong exception
00351  * safety if the container is a std::list or std::deque container (the
00352  * default is std::list), except that if std::deque is used as the
00353  * container and the copy constructor, move constructor, assignment
00354  * operator or move assignment operator of the queue item throws, it
00355  * only gives the basic exception guarantee (and the basic guarantee
00356  * is not given by std::deque if the queue item's move constructor
00357  * throws and it uses a non-default allocator which does not provide
00358  * for it to be CopyInsertable).  It is thread safe.
00359  * @param obj The item to be pushed onto the queue.
00360  * @exception std::bad_alloc The method might throw std::bad_alloc if
00361  * memory is exhausted and the system throws in that case.  It might
00362  * also throw if the copy constructor, move constructor, assignment
00363  * operator or move assignment operator of the queue item might throw.
00364  */
00365   void push(const value_type& obj) {
00366     Thread::Mutex::Lock lock{mutex};
00367     q.push(obj);
00368     cond.signal();
00369   }
00370 
00371 /**
00372  * Pushes an item onto the queue.  This method has strong exception
00373  * safety if the container is a std::list or std::deque container (the
00374  * default is std::list), except that if std::deque is used as the
00375  * container and the copy constructor, move constructor, assignment
00376  * operator or move assignment operator of the queue item throws, it
00377  * only gives the basic exception guarantee (and the basic guarantee
00378  * is not given by std::deque if the queue item's move constructor
00379  * throws and it uses a non-default allocator which does not provide
00380  * for it to be CopyInsertable).  It is thread safe.
00381  * @param obj The item to be pushed onto the queue.
00382  * @exception std::bad_alloc The method might throw std::bad_alloc if
00383  * memory is exhausted and the system throws in that case.  It might
00384  * also throw if the copy constructor, move constructor, assignment
00385  * operator or move assignment operator of the queue item might throw.
00386  *
00387  * Since 2.0.0-rc5
00388  */
00389   void push(value_type&& obj) {
00390     Thread::Mutex::Lock lock{mutex};
00391     q.push(std::move(obj));
00392     cond.signal();
00393   }
00394 
00395 /**
00396  * Pushes an item onto the queue by constructing it in place: that is,
00397  * by passing to this method the item's constructor's arguments,
00398  * rather than the item itself.  This method has strong exception
00399  * safety if the container is a std::list or std::deque container (the
00400  * default is std::list).  (Technically, for a std::deque container,
00401  * emplace() only offers the same exception guarantees as does push(),
00402  * namely only the basic guarantee where a copy or move of the queue
00403  * item throws during the call, but the purpose of emplace is to
00404  * construct in place and any reasonable implementation will not copy
00405  * or move the queue item.)  It is thread safe.
00406  * @param args The constructor arguments for the item to be pushed
00407  * onto the queue.
00408  * @exception std::bad_alloc The method might throw std::bad_alloc if
00409  * memory is exhausted and the system throws in that case.  It might
00410  * also throw if the item's constructor (including any of its
00411  * constructor arguments) might throw when constructing the item.
00412  * @note The constructor of the item pushed onto the queue must not
00413  * access any of the methods of the same queue object, or a deadlock
00414  * might occur.
00415  *
00416  * Since 2.0.0-rc5
00417  */
00418   template<class... Args>
00419   void emplace(Args&&... args) {
00420     Thread::Mutex::Lock lock{mutex};
00421     q.emplace(std::forward<Args>(args)...);
00422     cond.signal();
00423   }
00424 
00425 /**
00426  * Pops an item from the queue.  This method has strong exception
00427  * safety if the container is a std::deque or std::list container (the
00428  * default is std::list), provided the destructor of a contained item
00429  * does not throw.  It is thread safe.
00430  * @param obj A value type reference to which the item at the front of
00431  * the queue will be assigned.
00432  * @exception AsyncQueuePopError If the queue is empty when a pop is
00433  * attempted, this method will throw AsyncQueuePopError.  It might
00434  * also throw if the assignment operator of the queue item might
00435  * throw.  In order to complete pop() operations atomically under a
00436  * single lock and to retain strong exception safety, the object into
00437  * which the pop()ed data is to be placed is passed as an argument by
00438  * reference (this avoids a copy from a temporary object after the
00439  * data has been extracted from the queue, which would occur if the
00440  * item extracted were returned by value).  It might also throw if the
00441  * destructor of the queue item might throw (but that should never
00442  * happen), or if the empty() method of the container type throws
00443  * (which would not happen on any sane implementation).
00444  */
00445   void pop(value_type& obj) {
00446     Thread::Mutex::Lock lock{mutex};
00447     if (q.empty()) throw AsyncQueuePopError();
00448     obj = q.front();
00449     q.pop();
00450   }
00451 
00452 /**
00453  * Pops an item from the queue.  If the queue is empty, it will block
00454  * until an item becomes available.  If it blocks, the wait comprises
00455  * a cancellation point.  This method is cancellation safe if the
00456  * stack unwinds on cancellation, as cancellation is blocked while the
00457  * queue is being operated on after coming out of a wait.  This method
00458  * has strong exception safety if the container is a std::deque or
00459  * std::list container (the default is std::list), provided the
00460  * destructor of a contained item does not throw.  It is thread safe.
00461  * @param obj A value type reference to which the item at the front of
00462  * the queue will be assigned.  This method might throw if the
00463  * assignment operator of the queue item might throw.  In order to
00464  * complete pop() operations atomically under a single lock and to
00465  * retain strong exception safety, the object into which the pop()ed
00466  * data is to be placed is passed as an argument by reference (this
00467  * avoids a copy from a temporary object after the data has been
00468  * extracted from the queue, which would occur if the item extracted
00469  * were returned by value).  It might also throw if the destructor of
00470  * the queue item might throw (but that should never happen), or if
00471  * the empty() method of the container type throws (which would not
00472  * happen on any sane implementation).
00473  */
00474   void pop_dispatch(value_type& obj) {
00475     Thread::Mutex::Lock lock{mutex};
00476     while (q.empty()) cond.wait(mutex);
00477     Thread::CancelBlock b;
00478     obj = q.front();
00479     q.pop();
00480   }    
00481 
00482 /**
00483  * Pops an item from the queue.  If the queue is empty, it will block
00484  * until an item becomes available or until the timeout expires.  If
00485  * it blocks, the wait comprises a cancellation point.  This method is
00486  * cancellation safe if the stack unwinds on cancellation, as
00487  * cancellation is blocked while the queue is being operated on after
00488  * coming out of a wait.  This method has strong exception safety if
00489  * the container is a std::deque or std::list container (the default
00490  * is std::list), provided the destructor of a contained item does not
00491  * throw.  It is thread safe.
00492  * @param obj A value type reference to which the item at the front of
00493  * the queue will be assigned.  This method might throw if the
00494  * assignment operator of the queue item might throw.  In order to
00495  * complete pop() operations atomically under a single lock and to
00496  * retain strong exception safety, the object into which the pop()ed
00497  * data is to be placed is passed as an argument by reference (this
00498  * avoids a copy from a temporary object after the data has been
00499  * extracted from the queue, which would occur if the item extracted
00500  * were returned by value).  It might also throw if the destructor of
00501  * the queue item might throw (but that should never happen), or if
00502  * the empty() method of the container type throws (which would not
00503  * happen on any sane implementation).
00504  * @param millisec The timeout interval, in milliseconds.
00505  * @return If the timeout expires without an item becoming available,
00506  * the method will return true.  If an item from the queue is
00507  * extracted, it returns false.
00508  */
00509   bool pop_timed_dispatch(value_type& obj, unsigned int millisec) {
00510     timespec ts;
00511     Thread::Cond::get_abs_time(ts, millisec);
00512     Thread::Mutex::Lock lock{mutex};
00513     while (q.empty()) {
00514       if (cond.timed_wait(mutex, ts)) return true;
00515     }
00516     Thread::CancelBlock b;
00517     obj = q.front();
00518     q.pop();
00519     return false;
00520   }
00521 
00522 /**
00523  * Discards the item at the front of the queue.  This method has
00524  * strong exception safety if the container is a std::deque or
00525  * std::list container (the default is std::list), provided the
00526  * destructor of a contained item does not throw.  It is thread safe.
00527  * @exception AsyncQueuePopError If the queue is empty when a pop is
00528  * attempted, this method will throw AsyncQueuePopError.  It might
00529  * also throw if the destructor of the queue item might throw (but
00530  * that should never happen), or if the empty() method of the
00531  * container type throws (which would not happen on any sane
00532  * implementation).
00533  */
00534   void pop() {
00535     Thread::Mutex::Lock lock{mutex};
00536     if (q.empty()) throw AsyncQueuePopError();
00537     q.pop();
00538   }
00539 
00540 /**
00541  * @return Whether the queue is empty.  It will not throw assuming
00542  * that the empty() method of the container type does not throw, as it
00543  * will not on any sane implementation.
00544  * @note This method is thread safe, but the return value may not be
00545  * valid if another thread has pushed to or popped from the queue
00546  * before the value returned by the method is acted on.  It is
00547  * provided as a utility, but may not be meaningful, depending on the
00548  * intended usage.
00549  */
00550   bool empty() const {
00551     Thread::Mutex::Lock lock{mutex};
00552     return q.empty();
00553   }
00554 
00555 /**
00556  * @exception std::bad_alloc The constructor might throw this
00557  * exception if memory is exhausted and the system throws in that
00558  * case.
00559  * @exception Thread::MutexError The constructor might throw this
00560  * exception if initialisation of the contained mutex fails.  (It is
00561  * often not worth checking for this, as it means either memory is
00562  * exhausted or pthread has run out of other resources to create new
00563  * mutexes.)
00564  * @exception Thread::CondError The constructor might throw this
00565  * exception if initialisation of the contained condition variable
00566  * fails.  (It is often not worth checking for this, as it means
00567  * either memory is exhausted or pthread has run out of other
00568  * resources to create new condition variables.)
00569  */
00570   AsyncQueueDispatch() = default;
00571 
00572   // AsyncQueueDispatch objects cannot be copied - they are mainly
00573   // intended to pass data between two known threads
00574 /**
00575  * This class cannot be copied.  The copy constructor is deleted.
00576  */
00577   AsyncQueueDispatch(const AsyncQueueDispatch&) = delete;
00578 
00579 /**
00580  * This class cannot be copied.  The assignment operator is deleted.
00581  */
00582   AsyncQueueDispatch& operator=(const AsyncQueueDispatch&) = delete;
00583 
00584 /**
00585  * The destructor does not throw unless the destructor of a contained
00586  * item throws.  It is thread safe (any thread may delete the
00587  * AsyncQueueDispatch object).
00588  */
00589   ~AsyncQueueDispatch() {
00590     // lock and unlock the mutex in the destructor so that we have an
00591     // acquire operation to ensure that when the std::queue object is
00592     // destroyed memory is synchronised, so any thread may destroy the
00593     // AsyncQueueDispatch object
00594     Thread::Mutex::Lock lock{mutex};
00595   }
00596 
00597 /* Only has effect if --with-glib-memory-slices-compat or
00598  * --with-glib-memory-slices-no-compat option picked */
00599   CGU_GLIB_MEMORY_SLICES_FUNCS
00600 };
00601 
00602 } // namespace Cgu
00603 
00604 #endif