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