c++-gtk-utils
|
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