c++-gtk-utils
async_queue.h
Go to the documentation of this file.
1 /* Copyright (C) 2006 to 2014 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 /**
40  * @file async_queue.h
41  * @brief This file provides thread-safe asynchronous queue classes.
42  *
43  * AsyncQueue is a class which provides some of the functionality of a
44  * std::queue object (but note that the AsyncQueue::pop(value_type&
45  * obj) and AsyncQueue::move_pop(value_type& obj) methods provide the
46  * popped element by reference - see the comments on that method for
47  * the reason), except that it has mutex locking of the data container
48  * so as to permit pushing and popping from different threads. It is
49  * therefore useful for passing data between threads, perhaps in
50  * response to a signal being emitted from a Notifier object. Data
51  * can be pushed or pulled by move constructor/move assignment
52  * operator or by means of a std::unique_ptr object, SharedLockPtr
53  * object or an IntrusivePtr object referencing data derived from
54  * IntrusiveLockCounter.
55  *
56  * AsyncQueueDispatch is a class which has blocking pop() and
57  * move_pop() methods, which allows it to be waited on by a dedicated
58  * event/message dispatching thread for incoming work (represented by
59  * the data pushed onto the queue). In the same way, it can be used
60  * to implement thread pools, by having threads in the pool waiting on
61  * the queue.
62  *
63  * By default the queues use a std::list object as their container
64  * because when adding an item to the queue all allocation can take
65  * place outside the queue object's mutex. However, for types which
66  * have low overhead copy or move constructors, this can be changed
67  * to, say, a std::deque object by specifying it as the second
68  * template parameter.
69  */
70 
71 #ifndef CGU_ASYNC_QUEUE_H
72 #define CGU_ASYNC_QUEUE_H
73 
74 #include <queue>
75 #include <list>
76 #include <exception>
77 #include <utility> // for std::move and std::forward
78 #include <algorithm> // for std::swap
79 #include <time.h>
80 
81 #include <pthread.h>
82 
83 #include <c++-gtk-utils/mutex.h>
84 #include <c++-gtk-utils/thread.h>
86 
87 #ifdef CGU_USE_SCHED_YIELD
88 #include <sched.h>
89 #else
90 #include <unistd.h>
91 #endif
92 
93 namespace Cgu {
94 
95 /**
96  * @class AsyncQueuePopError async_queue.h c++-gtk-utils/async_queue.h
97  * @brief An exception thrown if calling pop() on a AsyncQueue or
98  * AsyncQueueDispatch object fails because the queue is empty.
99  * @sa AsyncQueue AsyncQueueDispatch
100  */
101 
102 struct AsyncQueuePopError: public std::exception {
103  virtual const char* what() const throw() {return "AsyncQueuePopError: popping from empty AsyncQueue object\n";}
104 };
105 
106 
107 /**
108  * @class AsyncQueue async_queue.h c++-gtk-utils/async_queue.h
109  * @brief A thread-safe asynchronous queue.
110  * @sa AsyncQueueDispatch AsyncChannel AsyncResult
111  *
112  * AsyncQueue is a class which provides some of the functionality of a
113  * std::queue object (but note that the AsyncQueue::pop(value_type&
114  * obj) and AsyncQueue::move_pop(value_type& obj) methods provide the
115  * popped element by reference - see the comments on that method for
116  * the reason), except that it has mutex locking of the data container
117  * so as to permit pushing and popping from different threads. It is
118  * therefore useful for passing data between threads, perhaps in
119  * response to a signal being emitted from a Notifier object. Data
120  * can be pushed or pulled by move constructor/move assignment
121  * operator or by means of a std::unique_ptr object, SharedLockPtr
122  * object or an IntrusivePtr object referencing data derived from
123  * IntrusiveLockCounter.
124  *
125  * By default the queue uses a std::list object as its container
126  * because when adding an item to the queue all allocation can take
127  * place outside the queue object's mutex. However, for types which
128  * have low overhead copy or move constructors, this can be changed
129  * to, say, a std::deque object by specifying it as the second
130  * template parameter.
131  *
132  * If the library is installed using the
133  * \--with-glib-memory-slices-compat or
134  * \--with-glib-memory-slices-no-compat configuration options, any
135  * AsyncQueue objects constructed on free store will be constructed in
136  * glib memory slices. This does not affect the queue container
137  * itself: to change the allocator of the C++ container, a custom
138  * allocator type can be provided when the AsyncQueue object is
139  * instantiated offering the standard allocator interface. If glib
140  * memory slices are not used or no AsyncQueue objects are constructed
141  * on free store, it is not necessary to call g_thread_init() before
142  * manipulating or using an AsyncQueue object in multiple threads, but
143  * prior to glib version 2.32 glib itself (and thus glib memory
144  * slices) are not thread safe unless that function has been called.
145  */
146 
147 template <class T, class Container = std::list<T> > class AsyncQueue {
148 public:
149  typedef typename Container::value_type value_type;
150  typedef typename Container::size_type size_type;
151  typedef Container container_type;
152 private:
153 // TODO: put 'q' after 'mutex' at the next ABI break, so move
154 // construction is strongly exception safe
155  std::queue<T, Container> q;
156  mutable Thread::Mutex mutex;
157 
158 // TODO: at the next ABI break make this method explicitly static
159 // this method won't throw: it is for the user to ensure the arguments
160 // do not refer to the same mutex object
161  void lock2(Thread::Mutex& m1, Thread::Mutex& m2) {
162  m1.lock();
163  for(;;) {
164  if (!m2.trylock()) {
165  return;
166  }
167  m1.unlock();
168  // spin nicely
169 #ifdef CGU_USE_SCHED_YIELD
170  sched_yield();
171 #else
172  usleep(10);
173 #endif
174  m1.lock();
175  }
176  }
177 public:
178 /**
179  * Pushes an item onto the queue. This method has strong exception
180  * safety if the container is a std::list or std::deque container (the
181  * default is std::list), except that if std::deque is used as the
182  * container and the copy constructor, move constructor, copy
183  * assignment operator or move assignment operator of the queue item
184  * throws, it only gives the basic exception guarantee (and the basic
185  * guarantee is not given by std::deque if the queue item's move
186  * constructor throws and it uses a non-default allocator which does
187  * not provide for it to be CopyInsertable). It is thread safe.
188  * @param obj The item to be pushed onto the queue.
189  * @exception std::bad_alloc The method might throw std::bad_alloc if
190  * memory is exhausted and the system throws in that case. It might
191  * also throw if the copy constructor, move constructor, assignment
192  * operator or move assignment operator of the queue item might throw.
193  */
194  void push(const value_type& obj) {
195  Thread::Mutex::Lock lock{mutex};
196  q.push(obj);
197  }
198 
199 /**
200  * Pushes an item onto the queue. This method has strong exception
201  * safety if the container is a std::list or std::deque container (the
202  * default is std::list), except that if std::deque is used as the
203  * container and the copy constructor, move constructor, copy
204  * assignment operator or move assignment operator of the queue item
205  * throws, it only gives the basic exception guarantee (and the basic
206  * guarantee is not given by std::deque if the queue item's move
207  * constructor throws and it uses a non-default allocator which does
208  * not provide for it to be CopyInsertable). It is thread safe.
209  * @param obj The item to be pushed onto the queue.
210  * @exception std::bad_alloc The method might throw std::bad_alloc if
211  * memory is exhausted and the system throws in that case. It might
212  * also throw if the copy constructor, move constructor, assignment
213  * operator or move assignment operator of the queue item might throw.
214  *
215  * Since 2.0.0-rc5
216  */
217  void push(value_type&& obj) {
218  Thread::Mutex::Lock lock{mutex};
219  q.push(std::move(obj));
220  }
221 
222 /**
223  * Pushes an item onto the queue by constructing it in place: that is,
224  * by passing to this method the item's constructor's arguments,
225  * rather than the item itself. This method has strong exception
226  * safety if the container is a std::list or std::deque container (the
227  * default is std::list). (Technically, for a std::deque container,
228  * emplace() only offers the same exception guarantees as does push(),
229  * namely only the basic guarantee where a copy or move of the queue
230  * item throws during the call, but the purpose of emplace is to
231  * construct in place and any reasonable implementation will not copy
232  * or move the queue item.) It is thread safe.
233  * @param args The constructor arguments for the item to be pushed
234  * onto the queue.
235  * @exception std::bad_alloc The method might throw std::bad_alloc if
236  * memory is exhausted and the system throws in that case. It might
237  * also throw if the item's constructor (including any of its
238  * constructor arguments) might throw when constructing the item.
239  * @note The constructor of the item pushed onto the queue must not
240  * access any of the methods of the same queue object, or a deadlock
241  * might occur.
242  *
243  * Since 2.0.0-rc5
244  */
245  template<class... Args>
246  void emplace(Args&&... args) {
247  Thread::Mutex::Lock lock{mutex};
248  q.emplace(std::forward<Args>(args)...);
249  }
250 
251 /**
252  * Pops an item from the queue using the contained type's copy
253  * assignment operator. This method has strong exception safety if
254  * the container is a std::deque or std::list container (the default
255  * is std::list), provided the destructor of a contained item does not
256  * throw. It is thread safe.
257  * @param obj A value type reference to which the item at the front of
258  * the queue will be assigned.
259  * @exception AsyncQueuePopError If the queue is empty when a pop is
260  * attempted, this method will throw AsyncQueuePopError. It might
261  * also throw if the copy assignment operator of the queue item might
262  * throw. In order to complete pop operations atomically under a
263  * single lock and to retain strong exception safety, the object into
264  * which the popped data is to be placed is passed as an argument by
265  * reference (this avoids a copy from a temporary object after the
266  * data has been extracted from the queue, which would occur if the
267  * item extracted were returned by value). It might also throw if the
268  * destructor of the queue item might throw (but that should never
269  * happen), or if the empty() method of the container type throws
270  * (which would not happen on any sane implementation).
271  */
272  void pop(value_type& obj) {
273  Thread::Mutex::Lock lock{mutex};
274  if (q.empty()) throw AsyncQueuePopError();
275  obj = q.front();
276  q.pop();
277  }
278 
279 /**
280  * Pops an item from the queue using the contained type's move
281  * assignment operator, if it has one. This method is identical to
282  * the pop() method if that type has no move assignment operator.
283  * This method has strong exception safety if the container is a
284  * std::deque or std::list container (the default is std::list),
285  * provided the destructor of a contained item does not throw and the
286  * move assignment operator of a contained item has strong exception
287  * safety. It is thread safe. Use this method in preference to the
288  * pop() method if it is known that the contained items' move
289  * assignment operator does not throw or is strongly exception safe,
290  * or if the use case does not require strong exception safety. This
291  * method (or the move_pop_basic() method) must be used in place of
292  * the pop() method if the contained type has a move assignment
293  * operator but no copy assignment operator (such as a std::unique_ptr
294  * object).
295  * @param obj A value type reference to which the item at the front of
296  * the queue will be move assigned.
297  * @exception AsyncQueuePopError If the queue is empty when a pop is
298  * attempted, this method will throw AsyncQueuePopError. It might
299  * also throw if the move assignment operator of the queue item might
300  * throw, or if it has no move assignment operator and its copy
301  * assignment operator throws. In order to complete pop operations
302  * atomically under a single lock and to retain strong exception
303  * safety, the object into which the popped data is to be placed is
304  * passed as an argument by reference (this avoids a move from a
305  * temporary object after the data has been extracted from the queue,
306  * which would occur if the item extracted were returned by value).
307  * It might also throw if the destructor of the queue item might throw
308  * (but that should never happen), or if the empty() method of the
309  * container type throws (which would not happen on any sane
310  * implementation).
311  *
312  * Since 2.0.11
313  */
314  void move_pop(value_type& obj) {
315  Thread::Mutex::Lock lock{mutex};
316  if (q.empty()) throw AsyncQueuePopError();
317  obj = std::move(q.front());
318  q.pop();
319  }
320 
321 /**
322  * Pops an item from the queue using the contained type's move
323  * assignment operator, if it has one, or if not using its copy
324  * assignment operator. This method is only available where the
325  * queue's container is a std::list object (which is the default), and
326  * does the same as the move_pop() method except that when popping the
327  * only thing which is done to the queue's container's internal state
328  * within the queue object's mutex is to swap some pointers: in
329  * particular, deallocation of the list node at the front of the queue
330  * occurs outside that mutex, as does assignment to this method's
331  * argument. Given that, if the queue's container is a list, any new
332  * node is also constructed outside the mutex when pushing or
333  * emplacing an item onto the queue, this minimizes contention between
334  * threads: it gets as close to lock-free performance as it is
335  * possible to get with the standard containers.
336  *
337  * However this minimizing of contention comes at a cost, which is
338  * that if the contained item's move assignment operator (or if it has
339  * none, its copy assignment operator) throws, then only the basic
340  * exception guarantee is offered (hence the name of this method).
341  * This means that although the AsyncQueue object would be left in a
342  * valid state in the event of such throwing, the item at the front of
343  * the queue would be lost. As in the case of the pop() and
344  * move_pop() methods, in addition only the basic exception guarantee
345  * is offered if the destructor of the contained item throws. Only
346  * use this method if the queue's container is a std::list object, and
347  * if either it is known that the contained item's move assignment
348  * operator (or if it has none, its copy assignment operator) does not
349  * throw, or the use case does not require strong exception safety.
350  * This method is thread safe.
351  *
352  * If this method is called for an AsyncQueue object whose container
353  * is not a std::list object, it will hand off to the move_pop()
354  * method, which is separately documented.
355  * @param obj A value type reference to which the item at the front of
356  * the queue will be move assigned.
357  * @exception AsyncQueuePopError If the queue is empty when a pop is
358  * attempted, this method will throw AsyncQueuePopError. It might
359  * also throw if the move assignment operator of the queue item might
360  * throw or it has no move assignment operator and its copy assignment
361  * operator throws (in which case only the basic exception guarantee
362  * is offered). It might also throw if the destructor of the queue
363  * item might throw (but that should never happen), if the empty()
364  * method of the container type throws (which would not happen on any
365  * sane implementation) or if the constructor of the implementation's
366  * list allocator throws (which would be highly unusual). In the
367  * event of any of the last two throwing, the strong exception
368  * guarantee is offered.
369  *
370  * Since 2.0.26
371  */
372 // See the specialisation for lists for the implementation of this
373 // method. For queues which do not use a list as their container,
374 // this hands off to move_pop().
375  void move_pop_basic(value_type& obj) {
376  move_pop(obj);
377  }
378 
379 /**
380  * Discards the item at the front of the queue. This method has
381  * strong exception safety if the container is a std::deque or
382  * std::list container (the default is std::list), provided the
383  * destructor of a contained item does not throw. It is thread safe.
384  * @exception AsyncQueuePopError If the queue is empty when a pop is
385  * attempted, this method will throw AsyncQueuePopError. It might
386  * also throw if the destructor of the queue item might throw (but
387  * that should never happen), or if the empty() method of the
388  * container type throws (which would not happen on any sane
389  * implementation).
390  */
391  void pop() {
392  Thread::Mutex::Lock lock{mutex};
393  if (q.empty()) throw AsyncQueuePopError();
394  q.pop();
395  }
396 
397 /**
398  * @return Whether the queue is empty. It will not throw assuming
399  * that the empty() method of the container type does not throw, as it
400  * will not on any sane implementation.
401  * @note This method is thread safe, but the return value may not be
402  * valid if another thread has pushed to or popped from the queue
403  * before the value returned by the method is acted on. It is
404  * provided as a utility, but may not be meaningful, depending on the
405  * intended usage.
406  */
407  bool empty() const {
408  Thread::Mutex::Lock lock{mutex};
409  return q.empty();
410  }
411 
412 /**
413  * @return The number of items currently in the queue. It will not
414  * throw assuming that the size() method of the container type does
415  * not throw, as it will not on any sane implementation.
416  * @note This method is thread safe, but the return value may not be
417  * valid if another thread has pushed to or popped from the queue
418  * before the value returned by the method is acted on. It is
419  * provided as a utility, but may not be meaningful, depending on the
420  * intended usage.
421  *
422  * Since 2.0.8
423  */
424  size_type size() const {
425  Thread::Mutex::Lock lock{mutex};
426  return q.size();
427  }
428 
429 /**
430  * Swaps the contents of 'this' and 'other'. It will not throw
431  * assuming that the swap method of the container type does not throw
432  * (which the C++11/14 standard requires not to happen with the
433  * standard sequence containers). It is thread safe and the swap is
434  * thread-wise atomic. A non-class function
435  * Cgu::swap(Cgu::AsyncQueue&, Cgu::AsyncQueue&) method is also
436  * provided which will call this method.
437  * @param other The object to be swapped with this one.
438  *
439  * Since 2.0.8
440  */
441  void swap(AsyncQueue& other) {
442  if (this != &other) {
443  lock2(mutex, other.mutex); // doesn't throw
445  Thread::Mutex::Lock l2{other.mutex, Thread::locked};
446  q.swap(other.q);
447  }
448  }
449 
450 /**
451  * The copy assignment operator is strongly exception safe with the
452  * standard sequence containers (it uses copy and swap). It is also
453  * thread safe, as it safely locks both the assignor's and assignee's
454  * mutex to provide a thread-wise atomic assignment.
455  * @param rhs The assignor.
456  * @return The AsyncQueue object after assignment.
457  * @exception std::bad_alloc The copy constructor of the queue's
458  * container type, and so this assignment operator, might throw
459  * std::bad_alloc if memory is exhausted and the system throws in that
460  * case. This assignment operator will also throw if the copy
461  * constructor of the queue's container type throws any other
462  * exceptions, including if any copy or move constructor or copy or
463  * move assignment operator of a contained item throws.
464  * @exception Thread::MutexError This assignment operator might throw
465  * Thread::MutexError if initialization of a transitional object's
466  * contained mutex fails. (It is often not worth checking for this,
467  * as it means either memory is exhausted or pthread has run out of
468  * other resources to create new mutexes.)
469  *
470  * Since 2.0.8
471  */
473  if (this != &rhs) {
474  lock2(mutex, rhs.mutex); // doesn't throw
476  Thread::Mutex::Lock l2{rhs.mutex, Thread::locked};
477  std::queue<T, Container> temp{rhs.q};
478  q.swap(temp);
479  }
480  return *this;
481  }
482 
483 /**
484  * This move assignment operator is thread safe as regards the
485  * assignee (the object moved to), but no synchronization is carried
486  * out with respect to the rvalue assignor/movant. This is because
487  * temporaries are only visible and accessible in the thread carrying
488  * out the move operation and synchronization for them would represent
489  * pointless overhead. In a case where the user uses std::move to
490  * force a move from a named object, and that named object's lifetime
491  * is managed by (or the object is otherwise accessed by) a different
492  * thread than the one making the move, the user must carry out her
493  * own synchronization with respect to that different thread, both to
494  * ensure that a consistent view of the the named object is obtained
495  * and because that object will be mutated by the move. This method
496  * invokes std::queue's move assignment operator, and therefore has
497  * the same exception safety as the standard library's implementation
498  * of that operator. It will not normally throw unless a custom
499  * allocator is used which throws on move assignment, or the
500  * destructor of a contained item throws.
501  * @param rhs The assignor/movant.
502  * @return The AsyncQueue object after move assignment.
503  *
504  * Since 2.0.8
505  */
507  Thread::Mutex::Lock lock{mutex};
508  q = std::move(rhs.q);
509  return *this;
510  }
511 
512 /**
513  * @exception std::bad_alloc The default constructor might throw
514  * std::bad_alloc if memory is exhausted and the system throws in that
515  * case.
516  * @exception Thread::MutexError The default constructor might throw
517  * Thread::MutexError if initialization of the contained mutex fails.
518  * (It is often not worth checking for this, as it means either memory
519  * is exhausted or pthread has run out of other resources to create
520  * new mutexes.)
521  */
522  AsyncQueue() = default;
523 
524 /**
525  * As regards thread safety, the move constructor does not synchronize
526  * with respect to the initializing rvalue. This is because
527  * temporaries are only visible and accessible in the thread carrying
528  * out the move operation and synchronization for them would represent
529  * pointless overhead. In a case where a user uses std::move to force
530  * a move from a named object, and that named object's lifetime is
531  * managed by (or the object is otherwise accessed by) a different
532  * thread than the one making the move, the user must carry out her
533  * own synchronization with respect to that different thread, both to
534  * ensure that a consistent view of the the named object is obtained
535  * and because that object will be mutated by the move.
536  * @param rhs The AsyncQueue object to be moved.
537  * @exception Thread::MutexError The move constructor might throw
538  * Thread::MutexError if initialization of the contained mutex fails.
539  * (It is often not worth checking for this, as it means either memory
540  * is exhausted or pthread has run out of other resources to create
541  * new mutexes.) It might also throw if the queue's container type's
542  * move constructor might throw, but it should not do that unless a
543  * custom allocator is in use.
544  * @note If this constructor throws Thread::MutexError, and a named
545  * object is moved using std::move, this constructor is not strongly
546  * exception safe (items in the moved queue will be lost). Fixing
547  * this efficiently requires changing the order of construction of
548  * data members of this class, which cannot be done until the next ABI
549  * break for this library as it would alter object layout. As noted
550  * above, in most cases the possibility of Thread::MutexError throwing
551  * can be ignored, but where that is not the case and strong exception
552  * safety is wanted, the user should either not employ std::move with
553  * named objects when invoking this class's constructors, or should
554  * construct an AsyncQueue object using the default constructor and
555  * then move assign to it.
556  *
557  * Since 2.0.8
558  */
559  AsyncQueue(AsyncQueue&& rhs): q(std::move(rhs.q)) {}
560 
561 /**
562  * The copy constructor is thread safe, as it locks the initializing
563  * object's mutex to obtain a consistent view of it.
564  * @param rhs The AsyncQueue object to be copied.
565  * @exception std::bad_alloc The copy constructor of the queue's
566  * container type, and so this constructor, might throw std::bad_alloc
567  * if memory is exhausted and the system throws in that case. It will
568  * also throw if the copy constructor of the queue's container type
569  * throws any other exceptions, including if any copy or move
570  * constructor or copy or move assignment operator of a contained item
571  * throws.
572  * @exception Thread::MutexError The copy constructor might throw
573  * Thread::MutexError if initialization of the contained mutex fails.
574  * (It is often not worth checking for this, as it means either memory
575  * is exhausted or pthread has run out of other resources to create
576  * new mutexes.)
577  *
578  * Since 2.0.8
579  */
580  // we use the comma operator here to lock the mutex and call the
581  // copy constructor: the lock will be retained until the end of the
582  // full expression in which it is lexically situated, namely until
583  // the end of q's constructor - see C++11 1.9/10 and 12.2/3
584  AsyncQueue(const AsyncQueue& rhs): q((Thread::Mutex::Lock(rhs.mutex), rhs.q)) {}
585 
586 /**
587  * The destructor does not throw unless the destructor of a contained
588  * item throws. It is thread safe (any thread may delete the
589  * AsyncQueue object).
590  */
592  // lock and unlock the mutex in the destructor so that we have an
593  // acquire operation to ensure that when the std::queue object is
594  // destroyed memory is synchronised, so any thread may destroy the
595  // AsyncQueue object
596  Thread::Mutex::Lock lock{mutex};
597  }
598 
599 /* Only has effect if --with-glib-memory-slices-compat or
600  * --with-glib-memory-slices-no-compat option picked */
602 };
603 
604 /**
605  * @class AsyncQueueDispatch async_queue.h c++-gtk-utils/async_queue.h
606  * @brief A thread-safe asynchronous queue with a blocking pop()
607  * method.
608  * @sa AsyncQueue AsyncChannel AsyncResult
609  *
610  * AsyncQueueDispatch is a class which has blocking pop_dispatch()
611  * and move_pop_dispatch() methods, which allows it to be waited on by a dedicated
612  * event/message dispatching thread for incoming work (represented by
613  * the data pushed onto the queue). In the same way, it can be used
614  * to implement thread pools, by having threads in the pool waiting on
615  * the queue. The AsyncResult class can be useful for passing results
616  * between threads in conjunction with AsyncQueueDispatch (the
617  * documentation on AsyncResult gives an example).
618  *
619  * By default the queue uses a std::list object as its container
620  * because when adding an item to the queue all allocation can take
621  * place outside the queue object's mutex. However, for types which
622  * have low overhead copy or move constructors, this can be changed
623  * to, say, a std::deque object by specifying it as the second
624  * template parameter.
625  *
626  * If the library is installed using the
627  * \--with-glib-memory-slices-compat or
628  * \--with-glib-memory-slices-no-compat configuration options, any
629  * AsyncQueueDispatch objects constructed on free store will be
630  * constructed in glib memory slices. This does not affect the queue
631  * container itself: to change the allocator of the C++ container, a
632  * custom allocator type can be provided when the AsyncQueueDispatch
633  * object is instantiated offering the standard allocator interface.
634  * If glib memory slices are not used or no AsyncQueueDispatch objects
635  * are constructed on free store, it is not necessary to call
636  * g_thread_init() before manipulating or using an AsyncQueueDispatch
637  * object in multiple threads, but prior to glib version 2.32 glib
638  * itself (and thus glib memory slices) are not thread safe unless
639  * that function has been called.
640  */
641 
642 template <class T, class Container = std::list<T> > class AsyncQueueDispatch {
643 public:
644  typedef typename Container::value_type value_type;
645  typedef typename Container::size_type size_type;
646  typedef Container container_type;
647 private:
648 // TODO: put 'q' after 'mutex' and 'cond' at the next ABI break, so
649 // move construction is strongly exception safe
650  std::queue<T, Container> q;
651  mutable Thread::Mutex mutex;
652  Thread::Cond cond;
653 
654 // TODO: at the next ABI break make this method explicitly static
655 // this method won't throw: it is for the user to ensure the arguments
656 // do not refer to the same mutex object
657  void lock2(Thread::Mutex& m1, Thread::Mutex& m2) {
658  m1.lock();
659  for(;;) {
660  if (!m2.trylock()) {
661  return;
662  }
663  m1.unlock();
664  // spin nicely
665 #ifdef CGU_USE_SCHED_YIELD
666  sched_yield();
667 #else
668  usleep(10);
669 #endif
670  m1.lock();
671  }
672  }
673 public:
674 /**
675  * Pushes an item onto the queue. This method has strong exception
676  * safety if the container is a std::list or std::deque container (the
677  * default is std::list), except that if std::deque is used as the
678  * container and the copy constructor, move constructor, copy
679  * assignment operator or move assignment operator of the queue item
680  * throws, it only gives the basic exception guarantee (and the basic
681  * guarantee is not given by std::deque if the queue item's move
682  * constructor throws and it uses a non-default allocator which does
683  * not provide for it to be CopyInsertable). It is thread safe.
684  * @param obj The item to be pushed onto the queue.
685  * @exception std::bad_alloc The method might throw std::bad_alloc if
686  * memory is exhausted and the system throws in that case. It might
687  * also throw if the copy constructor, move constructor, assignment
688  * operator or move assignment operator of the queue item might throw.
689  */
690  void push(const value_type& obj) {
691  Thread::Mutex::Lock lock{mutex};
692  q.push(obj);
693  cond.signal();
694  }
695 
696 /**
697  * Pushes an item onto the queue. This method has strong exception
698  * safety if the container is a std::list or std::deque container (the
699  * default is std::list), except that if std::deque is used as the
700  * container and the copy constructor, move constructor, copy
701  * assignment operator or move assignment operator of the queue item
702  * throws, it only gives the basic exception guarantee (and the basic
703  * guarantee is not given by std::deque if the queue item's move
704  * constructor throws and it uses a non-default allocator which does
705  * not provide for it to be CopyInsertable). It is thread safe.
706  * @param obj The item to be pushed onto the queue.
707  * @exception std::bad_alloc The method might throw std::bad_alloc if
708  * memory is exhausted and the system throws in that case. It might
709  * also throw if the copy constructor, move constructor, assignment
710  * operator or move assignment operator of the queue item might throw.
711  *
712  * Since 2.0.0-rc5
713  */
714  void push(value_type&& obj) {
715  Thread::Mutex::Lock lock{mutex};
716  q.push(std::move(obj));
717  cond.signal();
718  }
719 
720 /**
721  * Pushes an item onto the queue by constructing it in place: that is,
722  * by passing to this method the item's constructor's arguments,
723  * rather than the item itself. This method has strong exception
724  * safety if the container is a std::list or std::deque container (the
725  * default is std::list). (Technically, for a std::deque container,
726  * emplace() only offers the same exception guarantees as does push(),
727  * namely only the basic guarantee where a copy or move of the queue
728  * item throws during the call, but the purpose of emplace is to
729  * construct in place and any reasonable implementation will not copy
730  * or move the queue item.) It is thread safe.
731  * @param args The constructor arguments for the item to be pushed
732  * onto the queue.
733  * @exception std::bad_alloc The method might throw std::bad_alloc if
734  * memory is exhausted and the system throws in that case. It might
735  * also throw if the item's constructor (including any of its
736  * constructor arguments) might throw when constructing the item.
737  * @note The constructor of the item pushed onto the queue must not
738  * access any of the methods of the same queue object, or a deadlock
739  * might occur.
740  *
741  * Since 2.0.0-rc5
742  */
743  template<class... Args>
744  void emplace(Args&&... args) {
745  Thread::Mutex::Lock lock{mutex};
746  q.emplace(std::forward<Args>(args)...);
747  cond.signal();
748  }
749 
750 /**
751  * Pops an item from the queue using the contained type's copy
752  * assignment operator. This method has strong exception safety if
753  * the container is a std::deque or std::list container (the default
754  * is std::list), provided the destructor of a contained item does not
755  * throw. It is thread safe.
756  * @param obj A value type reference to which the item at the front of
757  * the queue will be assigned.
758  * @exception AsyncQueuePopError If the queue is empty when a pop is
759  * attempted, this method will throw AsyncQueuePopError. It might
760  * also throw if the copy assignment operator of the queue item might
761  * throw. In order to complete pop operations atomically under a
762  * single lock and to retain strong exception safety, the object into
763  * which the popped data is to be placed is passed as an argument by
764  * reference (this avoids a copy from a temporary object after the
765  * data has been extracted from the queue, which would occur if the
766  * item extracted were returned by value). It might also throw if the
767  * destructor of the queue item might throw (but that should never
768  * happen), or if the empty() method of the container type throws
769  * (which would not happen on any sane implementation).
770  */
771  void pop(value_type& obj) {
772  Thread::Mutex::Lock lock{mutex};
773  if (q.empty()) throw AsyncQueuePopError();
774  obj = q.front();
775  q.pop();
776  }
777 
778 /**
779  * Pops an item from the queue using the contained type's move
780  * assignment operator, if it has one. This method is identical to
781  * the pop() method if that type has no move assignment operator.
782  * This method has strong exception safety if the container is a
783  * std::deque or std::list container (the default is std::list),
784  * provided the destructor of a contained item does not throw and the
785  * move assignment operator of a contained item has strong exception
786  * safety. It is thread safe. Use this method in preference to the
787  * pop() method if it is known that the contained items' move
788  * assignment operator does not throw or is strongly exception safe,
789  * or if the use case does not require strong exception safety. This
790  * method (or the move_pop_basic() method) must be used in place of
791  * the pop() method if the contained type has a move assignment
792  * operator but no copy assignment operator (such as a std::unique_ptr
793  * object).
794  * @param obj A value type reference to which the item at the front of
795  * the queue will be move assigned.
796  * @exception AsyncQueuePopError If the queue is empty when a pop is
797  * attempted, this method will throw AsyncQueuePopError. It might
798  * also throw if the move assignment operator of the queue item might
799  * throw, or if it has no move assignment operator and its copy
800  * assignment operator throws. In order to complete pop operations
801  * atomically under a single lock and to retain strong exception
802  * safety, the object into which the popped data is to be placed is
803  * passed as an argument by reference (this avoids a move from a
804  * temporary object after the data has been extracted from the queue,
805  * which would occur if the item extracted were returned by value).
806  * It might also throw if the destructor of the queue item might throw
807  * (but that should never happen), or if the empty() method of the
808  * container type throws (which would not happen on any sane
809  * implementation).
810  *
811  * Since 2.0.11
812  */
813  void move_pop(value_type& obj) {
814  Thread::Mutex::Lock lock{mutex};
815  if (q.empty()) throw AsyncQueuePopError();
816  obj = std::move(q.front());
817  q.pop();
818  }
819 
820 /**
821  * Pops an item from the queue using the contained type's move
822  * assignment operator, if it has one, or if not using its copy
823  * assignment operator. This method is only available where the
824  * queue's container is a std::list object (which is the default), and
825  * does the same as the move_pop() method except that when popping the
826  * only thing which is done to the queue's container's internal state
827  * within the queue object's mutex is to swap some pointers: in
828  * particular, deallocation of the list node at the front of the queue
829  * occurs outside that mutex, as does assignment to this method's
830  * argument. Given that, if the queue's container is a list, any new
831  * node is also constructed outside the mutex when pushing or
832  * emplacing an item onto the queue, this minimizes contention between
833  * threads: it gets as close to lock-free performance as it is
834  * possible to get with the standard containers.
835  *
836  * However this minimizing of contention comes at a cost, which is
837  * that if the contained item's move assignment operator (or if it has
838  * none, its copy assignment operator) throws, then only the basic
839  * exception guarantee is offered (hence the name of this method).
840  * This means that although the AsyncQueueDispatch object would be
841  * left in a valid state in the event of such throwing, the item at
842  * the front of the queue would be lost. As in the case of the pop()
843  * and move_pop() methods, in addition only the basic exception
844  * guarantee is offered if the destructor of the contained item
845  * throws. Only use this method if the queue's container is a
846  * std::list object, and if either it is known that the contained
847  * item's move assignment operator (or if it has none, its copy
848  * assignment operator) does not throw, or the use case does not
849  * require strong exception safety. This method is thread safe.
850  *
851  * If this method is called for an AsyncQueueDispatch object whose
852  * container is not a std::list object, it will hand off to the
853  * move_pop() method, which is separately documented.
854  * @param obj A value type reference to which the item at the front of
855  * the queue will be move assigned.
856  * @exception AsyncQueuePopError If the queue is empty when a pop is
857  * attempted, this method will throw AsyncQueuePopError. It might
858  * also throw if the move assignment operator of the queue item might
859  * throw or it has no move assignment operator and its copy assignment
860  * operator throws (in which case only the basic exception guarantee
861  * is offered). It might also throw if the destructor of the queue
862  * item might throw (but that should never happen), if the empty()
863  * method of the container type throws (which would not happen on any
864  * sane implementation) or if the constructor of the implementation's
865  * list allocator throws (which would be highly unusual). In the
866  * event of any of the last two throwing, the strong exception
867  * guarantee is offered.
868  *
869  * Since 2.0.26
870  */
871 // See the specialisation for lists for the implementation of this
872 // method. For queues which do not use a list as their container,
873 // this hands off to move_pop().
874  void move_pop_basic(value_type& obj){
875  move_pop(obj);
876  }
877 
878 /**
879  * Pops an item from the queue using the contained type's copy
880  * assignment operator. If the queue is empty, it will block until an
881  * item becomes available. If it blocks, the wait comprises a
882  * cancellation point. This method is cancellation safe if the stack
883  * unwinds on cancellation, as cancellation is blocked while the queue
884  * is being operated on after coming out of a wait. This method has
885  * strong exception safety if the container is a std::deque or
886  * std::list container (the default is std::list), provided the
887  * destructor of a contained item does not throw. It is thread safe.
888  * @param obj A value type reference to which the item at the front of
889  * the queue will be assigned. This method might throw if the copy
890  * assignment operator of the queue item might throw. In order to
891  * complete pop operations atomically under a single lock and to
892  * retain strong exception safety, the object into which the popped
893  * data is to be placed is passed as an argument by reference (this
894  * avoids a copy from a temporary object after the data has been
895  * extracted from the queue, which would occur if the item extracted
896  * were returned by value). It might also throw if the destructor of
897  * the queue item might throw (but that should never happen), or if
898  * the empty() method of the container type throws (which would not
899  * happen on any sane implementation).
900  */
901  void pop_dispatch(value_type& obj) {
902  Thread::Mutex::Lock lock{mutex};
903  while (q.empty()) cond.wait(mutex);
905  obj = q.front();
906  q.pop();
907  }
908 
909 /**
910  * Pops an item from the queue using the contained type's move
911  * assignment operator, if it has one (this method is identical to the
912  * pop_dispatch() method if that type has no move assignment
913  * operator). If the queue is empty, it will block until an item
914  * becomes available. If it blocks, the wait comprises a cancellation
915  * point. This method is cancellation safe if the stack unwinds on
916  * cancellation, as cancellation is blocked while the queue is being
917  * operated on after coming out of a wait. This method has strong
918  * exception safety if the container is a std::deque or std::list
919  * container (the default is std::list), provided the destructor of a
920  * contained item does not throw and the move assignment operator of a
921  * contained item has strong exception safety. It is thread safe.
922  * Use this method in preference to the pop_dispatch() method if it is
923  * known that the contained items' move assignment operator does not
924  * throw or is strongly exception safe, or if the use case does not
925  * require strong exception safety. This method (or the
926  * move_pop_dispatch_basic() method) must be used in place of the
927  * pop_dispatch() method if the contained type has a move assignment
928  * operator but no copy assignment operator (such as a std::unique_ptr
929  * object).
930  * @param obj A value type reference to which the item at the front of
931  * the queue will be move assigned. This method might throw if the
932  * move assignment operator of the queue item might throw, or if it
933  * has no move assignment operator and its copy assignment operator
934  * throws. In order to complete pop operations atomically under a
935  * single lock and to retain strong exception safety, the object into
936  * which the popped data is to be placed is passed as an argument by
937  * reference (this avoids a move from a temporary object after the
938  * data has been extracted from the queue, which would occur if the
939  * item extracted were returned by value). It might also throw if the
940  * destructor of the queue item might throw (but that should never
941  * happen), or if the empty() method of the container type throws
942  * (which would not happen on any sane implementation).
943  *
944  * Since 2.0.11
945  */
946  void move_pop_dispatch(value_type& obj) {
947  Thread::Mutex::Lock lock{mutex};
948  while (q.empty()) cond.wait(mutex);
950  obj = std::move(q.front());
951  q.pop();
952  }
953 
954 /**
955  * Pops an item from the queue using the contained type's move
956  * assignment operator, if it has one, or if not using its copy
957  * assignment operator. This method is only available where the
958  * queue's container is a std::list object (which is the default), and
959  * does the same as the move_pop_dispatch() method except that when
960  * popping the only thing which is done to the queue's container's
961  * internal state within the queue object's mutex is to swap some
962  * pointers: in particular, deallocation of the list node at the front
963  * of the queue occurs outside that mutex, as does assignment to this
964  * method's argument. Given that, if the queue's container is a list,
965  * any new node is also constructed outside the mutex when pushing or
966  * emplacing an item onto the queue, this minimizes contention between
967  * threads: it gets as close to lock-free performance as it is
968  * possible to get with the standard containers.
969  *
970  * However this minimizing of contention comes at a cost, which is
971  * that if the contained item's move assignment operator (or if it has
972  * none, its copy assignment operator) throws, then only the basic
973  * exception guarantee is offered (hence the name of this method).
974  * This means that although the AsyncQueueDispatch object would be
975  * left in a valid state in the event of such throwing, the item at
976  * the front of the queue would be lost. As in the case of the
977  * pop_dispatch() and move_pop_dispatch() methods, in addition only
978  * the basic exception guarantee is offered if the destructor of the
979  * contained item throws. Only use this method if the queue's
980  * container is a std::list object, and if either it is known that the
981  * contained item's move assignment operator (or if it has none, its
982  * copy assignment operator) does not throw, or the use case does not
983  * require strong exception safety. This method is thread safe.
984  *
985  * If the queue is empty, it will block until an item
986  * becomes available. If it blocks, the wait comprises a cancellation
987  * point. This method is cancellation safe if the stack unwinds on
988  * cancellation, as cancellation is blocked while the queue is being
989  * operated on after coming out of a wait.
990  *
991  * If this method is called for an AsyncQueueDispatch object whose
992  * container is not a std::list object, it will hand off to the
993  * move_pop_dispatch() method, which is separately documented.
994  * @param obj A value type reference to which the item at the front of
995  * the queue will be move assigned. This method might throw if the
996  * move assignment operator of the queue item might throw or it has no
997  * move assignment operator and its copy assignment operator throws
998  * (in which case only the basic exception guarantee is offered). It
999  * might also throw if the destructor of the queue item might throw
1000  * (but that should never happen), if the empty() method of the
1001  * container type throws (which would not happen on any sane
1002  * implementation) or if the constructor of the implementation's list
1003  * allocator throws (which would be highly unusual). In the event of
1004  * any of the last two throwing, the strong exception guarantee is
1005  * offered.
1006  *
1007  * Since 2.0.26
1008  */
1009 // See the specialisation for lists for the implementation of this
1010 // method. For queues which do not use a list as their container,
1011 // this hands off to move_pop_dispatch().
1012  void move_pop_dispatch_basic(value_type& obj) {
1013  move_pop_dispatch(obj);
1014  }
1015 
1016 /**
1017  * Pops an item from the queue using the contained type's copy
1018  * assignment operator. If the queue is empty, it will block until an
1019  * item becomes available or until the timeout expires. If it blocks,
1020  * the wait comprises a cancellation point. This method is
1021  * cancellation safe if the stack unwinds on cancellation, as
1022  * cancellation is blocked while the queue is being operated on after
1023  * coming out of a wait. This method has strong exception safety if
1024  * the container is a std::deque or std::list container (the default
1025  * is std::list), provided the destructor of a contained item does not
1026  * throw. It is thread safe.
1027  * @param obj A value type reference to which the item at the front of
1028  * the queue will be assigned. This method might throw if the copy
1029  * assignment operator of the queue item might throw. In order to
1030  * complete pop operations atomically under a single lock and to
1031  * retain strong exception safety, the object into which the popped
1032  * data is to be placed is passed as an argument by reference (this
1033  * avoids a copy from a temporary object after the data has been
1034  * extracted from the queue, which would occur if the item extracted
1035  * were returned by value). It might also throw if the destructor of
1036  * the queue item might throw (but that should never happen), or if
1037  * the empty() method of the container type throws (which would not
1038  * happen on any sane implementation).
1039  * @param millisec The timeout interval, in milliseconds.
1040  * @return If the timeout expires without an item becoming available,
1041  * the method will return true. If an item from the queue is
1042  * extracted, it returns false.
1043  */
1044  bool pop_timed_dispatch(value_type& obj, unsigned int millisec) {
1045  timespec ts;
1046  Thread::Cond::get_abs_time(ts, millisec);
1047  Thread::Mutex::Lock lock{mutex};
1048  while (q.empty()) {
1049  if (cond.timed_wait(mutex, ts)) return true;
1050  }
1052  obj = q.front();
1053  q.pop();
1054  return false;
1055  }
1056 
1057 /**
1058  * Pops an item from the queue using the contained type's move
1059  * assignment operator, if it has one (this method is identical to the
1060  * pop_timed_dispatch() method if that type has no move assignment
1061  * operator). If the queue is empty, it will block until an item
1062  * becomes available or until the timeout expires. If it blocks, the
1063  * wait comprises a cancellation point. This method is cancellation
1064  * safe if the stack unwinds on cancellation, as cancellation is
1065  * blocked while the queue is being operated on after coming out of a
1066  * wait. This method has strong exception safety if the container is
1067  * a std::deque or std::list container (the default is std::list),
1068  * provided the destructor of a contained item does not throw and the
1069  * move assignment operator of a contained item has strong exception
1070  * safety. It is thread safe. Use this method in preference to the
1071  * pop_timed_dispatch() method if it is known that the contained
1072  * items' move assignment operator does not throw or is strongly
1073  * exception safe, or if the use case does not require strong
1074  * exception safety. This method (or the
1075  * move_pop_timed_dispatch_basic() method) must be used in place of
1076  * the pop_timed_dispatch() method if the contained type has a move
1077  * assignment operator but no copy assignment operator (such as a
1078  * std::unique_ptr object).
1079  * @param obj A value type reference to which the item at the front of
1080  * the queue will be move assigned. This method might throw if the
1081  * move assignment operator of the queue item might throw, or if it
1082  * has no move assignment operator and its copy assignment operator
1083  * throws. In order to complete pop operations atomically under a
1084  * single lock and to retain strong exception safety, the object into
1085  * which the popped data is to be placed is passed as an argument by
1086  * reference (this avoids a move from a temporary object after the
1087  * data has been extracted from the queue, which would occur if the
1088  * item extracted were returned by value). It might also throw if the
1089  * destructor of the queue item might throw (but that should never
1090  * happen), or if the empty() method of the container type throws
1091  * (which would not happen on any sane implementation).
1092  * @param millisec The timeout interval, in milliseconds.
1093  * @return If the timeout expires without an item becoming available,
1094  * the method will return true. If an item from the queue is
1095  * extracted, it returns false.
1096  *
1097  * Since 2.0.11
1098  */
1099  bool move_pop_timed_dispatch(value_type& obj, unsigned int millisec) {
1100  timespec ts;
1101  Thread::Cond::get_abs_time(ts, millisec);
1102  Thread::Mutex::Lock lock{mutex};
1103  while (q.empty()) {
1104  if (cond.timed_wait(mutex, ts)) return true;
1105  }
1107  obj = std::move(q.front());
1108  q.pop();
1109  return false;
1110  }
1111 
1112 /**
1113  * Pops an item from the queue using the contained type's move
1114  * assignment operator, if it has one, or if not using its copy
1115  * assignment operator. This method is only available where the
1116  * queue's container is a std::list object (which is the default), and
1117  * does the same as the move_pop_timed_dispatch() method except that
1118  * when popping the only thing which is done to the queue's
1119  * container's internal state within the queue object's mutex is to
1120  * swap some pointers: in particular, deallocation of the list node at
1121  * the front of the queue occurs outside that mutex, as does
1122  * assignment to this method's argument. Given that, if the queue's
1123  * container is a list, any new node is also constructed outside the
1124  * mutex when pushing or emplacing an item onto the queue, this
1125  * minimizes contention between threads: it gets as close to lock-free
1126  * performance as it is possible to get with the standard containers.
1127  *
1128  * However this minimizing of contention comes at a cost, which is
1129  * that if the contained item's move assignment operator (or if it has
1130  * none, its copy assignment operator) throws, then only the basic
1131  * exception guarantee is offered (hence the name of this method).
1132  * This means that although the AsyncQueueDispatch object would be
1133  * left in a valid state in the event of such throwing, the item at
1134  * the front of the queue would be lost. As in the case of the
1135  * pop_timed_dispatch() and move_pop_timed_dispatch() methods, in
1136  * addition only the basic exception guarantee is offered if the
1137  * destructor of the contained item throws. Only use this method if
1138  * the queue's container is a std::list object, and if either it is
1139  * known that the contained item's move assignment operator (or if it
1140  * has none, its copy assignment operator) does not throw, or the use
1141  * case does not require strong exception safety. This method is
1142  * thread safe.
1143  *
1144  * If the queue is empty, it will block until an item becomes
1145  * available or until the timeout expires. If it blocks, the wait
1146  * comprises a cancellation point. This method is cancellation safe
1147  * if the stack unwinds on cancellation, as cancellation is blocked
1148  * while the queue is being operated on after coming out of a wait.
1149  *
1150  * If this method is called for an AsyncQueueDispatch object whose
1151  * container is not a std::list object, it will hand off to the
1152  * move_pop_timed_dispatch() method, which is separately documented.
1153  * @param obj A value type reference to which the item at the front of
1154  * the queue will be move assigned. This method might throw if the
1155  * move assignment operator of the queue item might throw or it has no
1156  * move assignment operator and its copy assignment operator throws
1157  * (in which case only the basic exception guarantee is offered). It
1158  * might also throw if the destructor of the queue item might throw
1159  * (but that should never happen), if the empty() method of the
1160  * container type throws (which would not happen on any sane
1161  * implementation) or if the constructor of the implementation's list
1162  * allocator throws (which would be highly unusual). In the event of
1163  * any of the last two throwing, the strong exception guarantee is
1164  * offered.
1165  * @param millisec The timeout interval, in milliseconds.
1166  * @return If the timeout expires without an item becoming available,
1167  * the method will return true. If an item from the queue is
1168  * extracted, it returns false.
1169  *
1170  * Since 2.0.26
1171  */
1172 // See the specialisation for lists for the implementation of this
1173 // method. For queues which do not use a list as their container,
1174 // this hands off to move_pop_timed_dispatch().
1175  bool move_pop_timed_dispatch_basic(value_type& obj, unsigned int millisec) {
1176  return move_pop_timed_dispatch(obj, millisec);
1177  }
1178 
1179 /**
1180  * Discards the item at the front of the queue. This method has
1181  * strong exception safety if the container is a std::deque or
1182  * std::list container (the default is std::list), provided the
1183  * destructor of a contained item does not throw. It is thread safe.
1184  * @exception AsyncQueuePopError If the queue is empty when a pop is
1185  * attempted, this method will throw AsyncQueuePopError. It might
1186  * also throw if the destructor of the queue item might throw (but
1187  * that should never happen), or if the empty() method of the
1188  * container type throws (which would not happen on any sane
1189  * implementation).
1190  */
1191  void pop() {
1192  Thread::Mutex::Lock lock{mutex};
1193  if (q.empty()) throw AsyncQueuePopError();
1194  q.pop();
1195  }
1196 
1197 /**
1198  * @return Whether the queue is empty. It will not throw assuming
1199  * that the empty() method of the container type does not throw, as it
1200  * will not on any sane implementation.
1201  * @note This method is thread safe, but the return value may not be
1202  * valid if another thread has pushed to or popped from the queue
1203  * before the value returned by the method is acted on. It is
1204  * provided as a utility, but may not be meaningful, depending on the
1205  * intended usage.
1206  */
1207  bool empty() const {
1208  Thread::Mutex::Lock lock{mutex};
1209  return q.empty();
1210  }
1211 
1212 /**
1213  * @return The number of items currently in the queue. It will not
1214  * throw assuming that the size() method of the container type does
1215  * not throw, as it will not on any sane implementation.
1216  * @note This method is thread safe, but the return value may not be
1217  * valid if another thread has pushed to or popped from the queue
1218  * before the value returned by the method is acted on. It is
1219  * provided as a utility, but may not be meaningful, depending on the
1220  * intended usage.
1221  *
1222  * Since 2.0.8
1223  */
1224  size_type size() const {
1225  Thread::Mutex::Lock lock{mutex};
1226  return q.size();
1227  }
1228 
1229 /**
1230  * Swaps the contents of 'this' and 'other'. It will not throw
1231  * assuming that the swap method of the container type does not throw
1232  * (which the C++11/14 standard requires not to happen with the
1233  * standard sequence containers). It is thread safe and the swap is
1234  * thread-wise atomic. A non-class function
1235  * Cgu::swap(Cgu::AsyncQueueDispatch&, Cgu::AsyncQueueDispatch&)
1236  * method is also provided which will call this method.
1237  * @param other The object to be swapped with this one.
1238  * @note An object swapped does not, by virtue of the swap, inherit
1239  * any threads waiting on the other one. However if threads were
1240  * waiting on a swapped object prior to the swap, and it acquires
1241  * items by virtue of the swap, the waiting threads will unblock and
1242  * extract those items.
1243  *
1244  * Since 2.0.8
1245  */
1246  void swap(AsyncQueueDispatch& other) {
1247  if (this != &other) {
1248  lock2(mutex, other.mutex); // doesn't throw
1250  Thread::Mutex::Lock l2{other.mutex, Thread::locked};
1251  q.swap(other.q);
1252  if (!q.empty()) cond.broadcast();
1253  if (!other.q.empty()) other.cond.broadcast();
1254  }
1255  }
1256 
1257 /**
1258  * The copy assignment operator is strongly exception safe with the
1259  * standard sequence containers (it uses copy and swap). It is also
1260  * thread safe, as it safely locks both the assignor's and assignee's
1261  * mutex to provide a thread-wise atomic assignment.
1262  * @param rhs The assignor.
1263  * @return The AsyncQueueDispatch object after assignment.
1264  * @exception std::bad_alloc The copy constructor of the queue's
1265  * container type, and so this assignment operator, might throw
1266  * std::bad_alloc if memory is exhausted and the system throws in that
1267  * case. This assignment operator will also throw if the copy
1268  * constructor of the queue's container type throws any other
1269  * exceptions, including if any copy or move constructor or copy or
1270  * move assignment operator of a contained item throws.
1271  * @exception Thread::MutexError This assignment operator might
1272  * throw Thread::MutexError if initialization of a transitional
1273  * object's contained mutex fails. (It is often not worth checking
1274  * for this, as it means either memory is exhausted or pthread has run
1275  * out of other resources to create new mutexes.)
1276  * @exception Thread::CondError This assignment operator might throw
1277  * Thread::CondError if initialisation of a transitional object's
1278  * contained condition variable fails. (It is often not worth
1279  * checking for this, as it means either memory is exhausted or
1280  * pthread has run out of other resources to create new condition
1281  * variables.)
1282  * @note The assignee does not, by virtue of the assignment, inherit
1283  * any threads waiting on the assignor. However, if prior to the
1284  * assignment threads were waiting on the assignee and the assignee
1285  * acquires items from the assignor as a result of the assignment, the
1286  * waiting threads will unblock and extract those items.
1287  *
1288  * Since 2.0.8
1289  */
1291  if (this != &rhs) {
1292  lock2(mutex, rhs.mutex); // doesn't throw
1294  Thread::Mutex::Lock l2{rhs.mutex, Thread::locked};
1295  std::queue<T, Container> temp{rhs.q};
1296  q.swap(temp);
1297  if (!q.empty()) cond.broadcast();
1298  }
1299  return *this;
1300  }
1301 
1302 /**
1303  * This move assignment operator is thread safe as regards the
1304  * assignee (the object moved to), but no synchronization is carried
1305  * out with respect to the rvalue assignor/movant. This is because
1306  * temporaries are only visible and accessible in the thread carrying
1307  * out the move operation and synchronization for them would represent
1308  * pointless overhead. In a case where the user uses std::move to
1309  * force a move from a named object, and that named object's lifetime
1310  * is managed by (or the object is otherwise accessed by) a different
1311  * thread than the one making the move, the user must carry out her
1312  * own synchronization with respect to that different thread, both to
1313  * ensure that a consistent view of the the named object is obtained
1314  * and because that object will be mutated by the move. This method
1315  * invokes std::queue's move assignment operator, and therefore has
1316  * the same exception safety as the standard library's implementation
1317  * of that operator. It will not normally throw unless a custom
1318  * allocator is used which throws on move assignment, or the
1319  * destructor of a contained item throws.
1320  * @param rhs The assignor/movant.
1321  * @return The AsyncQueueDispatch object after move assignment.
1322  * @note The assignee does not, by virtue of the move, inherit any
1323  * threads waiting on the assignor/movant. However, if prior to the
1324  * move threads were waiting on the assignee and the assignee acquires
1325  * items from the assignor/movant as a result of the move, from
1326  * version 2.0.9 the waiting threads will unblock and extract those
1327  * items (such unblocking on move assignment did not happen with
1328  * version 2.0.8, which was a bug).
1329  *
1330  * Since 2.0.8
1331  */
1333  Thread::Mutex::Lock lock{mutex};
1334  q = std::move(rhs.q);
1335  if (!q.empty()) cond.broadcast();
1336  return *this;
1337  }
1338 
1339 /**
1340  * @exception std::bad_alloc The default constructor might throw this
1341  * exception if memory is exhausted and the system throws in that
1342  * case.
1343  * @exception Thread::MutexError The default constructor might throw
1344  * this exception if initialisation of the contained mutex fails. (It
1345  * is often not worth checking for this, as it means either memory is
1346  * exhausted or pthread has run out of other resources to create new
1347  * mutexes.)
1348  * @exception Thread::CondError The default constructor might throw
1349  * this exception if initialisation of the contained condition
1350  * variable fails. (It is often not worth checking for this, as it
1351  * means either memory is exhausted or pthread has run out of other
1352  * resources to create new condition variables.)
1353  */
1354  AsyncQueueDispatch() = default;
1355 
1356 /**
1357  * As regards thread safety, the move constructor does not synchronize
1358  * with respect to the initializing rvalue. This is because
1359  * temporaries are only visible and accessible in the thread carrying
1360  * out the move operation and synchronization for them would represent
1361  * pointless overhead. In a case where a user uses std::move to force
1362  * a move from a named object, and that named object's lifetime is
1363  * managed by (or the object is otherwise accessed by) a different
1364  * thread than the one making the move, the user must carry out her
1365  * own synchronization with respect to that different thread, both to
1366  * ensure that a consistent view of the the named object is obtained
1367  * and because that object will be mutated by the move.
1368  * @param rhs The AsyncQueueDispatch object to be moved.
1369  * @exception Thread::MutexError The move constructor might throw
1370  * Thread::MutexError if initialization of the contained mutex fails.
1371  * (It is often not worth checking for this, as it means either memory
1372  * is exhausted or pthread has run out of other resources to create
1373  * new mutexes.) It might also throw if the queue's container type's
1374  * move constructor might throw, but it should not do that unless a
1375  * custom allocator is in use.
1376  * @exception Thread::CondError The move constructor might throw this
1377  * exception if initialisation of the contained condition variable
1378  * fails. (It is often not worth checking for this, as it means
1379  * either memory is exhausted or pthread has run out of other
1380  * resources to create new condition variables.) It might also throw
1381  * if the queue's container type's move constructor might throw, but
1382  * it should not do that unless a custom allocator is in use.
1383  * @note If this constructor throws Thread::MutexError or
1384  * Thread::CondError, and a named object is moved using std::move,
1385  * this constructor is not strongly exception safe (items in the moved
1386  * queue will be lost). Fixing this efficiently requires changing the
1387  * order of construction of data members of this class, which cannot
1388  * be done without an ABI break for this library as it would alter
1389  * object layout: this is therefore fixed in the 2.2 series of the
1390  * library but not in this series. As noted above, in most cases the
1391  * possibility of Thread::MutexError or Thread::CondError throwing can
1392  * be ignored, but where that is not the case and strong exception
1393  * safety is wanted, the user should either not employ std::move with
1394  * named objects when invoking this class's constructors, or should
1395  * construct an AsyncQueueDispatch object using the default
1396  * constructor and then move assign to it.
1397  *
1398  * Since 2.0.8
1399  */
1400  AsyncQueueDispatch(AsyncQueueDispatch&& rhs): q(std::move(rhs.q)) {}
1401 
1402 /**
1403  * The copy constructor is thread safe, as it locks the initializing
1404  * object's mutex to obtain a consistent view of it.
1405  * @param rhs The AsyncQueueDispatch object to be copied.
1406  * @exception std::bad_alloc The copy constructor of the queue's
1407  * container type, and so this constructor, might throw std::bad_alloc
1408  * if memory is exhausted and the system throws in that case. It will
1409  * also throw if the copy constructor of the queue's container type
1410  * throws any other exceptions, including if any copy or move
1411  * constructor or copy or move assignment operator of a contained item
1412  * throws.
1413  * @exception Thread::MutexError The copy constructor might throw
1414  * Thread::MutexError if initialization of the contained mutex fails.
1415  * (It is often not worth checking for this, as it means either memory
1416  * is exhausted or pthread has run out of other resources to create
1417  * new mutexes.)
1418  * @exception Thread::CondError The copy constructor might throw this
1419  * exception if initialisation of the contained condition variable
1420  * fails. (It is often not worth checking for this, as it means
1421  * either memory is exhausted or pthread has run out of other
1422  * resources to create new condition variables.)
1423  *
1424  * Since 2.0.8
1425  */
1426  // we use the comma operator here to lock the mutex and call the
1427  // copy constructor: the lock will be retained until the end of the
1428  // full expression in which it is lexically situated, namely until
1429  // the end of q's constructor - see C++11 1.9/10 and 12.2/3
1431  q((Thread::Mutex::Lock(rhs.mutex), rhs.q)) {}
1432 
1433 /**
1434  * The destructor does not throw unless the destructor of a contained
1435  * item throws. It is thread safe (any thread may delete the
1436  * AsyncQueueDispatch object). Destroying an AsyncQueueDispatch
1437  * object on which another thread is currently blocked results in
1438  * undefined behavior.
1439  */
1441  // lock and unlock the mutex in the destructor so that we have an
1442  // acquire operation to ensure that when the std::queue object is
1443  // destroyed memory is synchronised, so any thread may destroy the
1444  // AsyncQueueDispatch object
1445  Thread::Mutex::Lock lock{mutex};
1446  }
1447 
1448 /* Only has effect if --with-glib-memory-slices-compat or
1449  * --with-glib-memory-slices-no-compat option picked */
1451 };
1452 
1453 /**
1454  * Swaps the contents of two AsyncQueue objects. It will not throw
1455  * assuming that the swap method of the container type does not throw
1456  * (which the C++11/13 standard requires not to happen with the
1457  * standard sequence containers). It is thread safe and the swap is
1458  * thread-wise atomic.
1459  * @param q1 An object to be swapped with the other.
1460  * @param q2 An object to be swapped with the other.
1461  * @note Calling std::swap on AsyncQueue objects is thread safe but
1462  * does not provide a thread-wise atomic swap (the swapped objects may
1463  * not be mirror images if during the execution of std::swap's default
1464  * algorithm one of them has been modified), although in many cases
1465  * that doesn't matter. If swap() is called without a namespace
1466  * qualifier, argument dependent look-up will pick this one correctly.
1467  *
1468  * Since 2.0.8
1469  */
1470 template <class T, class Container>
1473  q1.swap(q2);
1474 }
1475 
1476 /**
1477  * Swaps the contents of two AsyncQueueDispatch objects. It will not
1478  * throw assuming that the swap method of the container type does not
1479  * throw (which the C++11/13 standard requires not to happen with the
1480  * standard sequence containers). It is thread safe and the swap is
1481  * thread-wise atomic.
1482  * @param q1 An object to be swapped with the other.
1483  * @param q2 An object to be swapped with the other.
1484  * @note 1. An object swapped does not, by virtue of the swap, inherit
1485  * any threads waiting on the other one. However if threads were
1486  * waiting on a swapped object prior to the swap, and it acquires
1487  * items by virtue of the swap, the waiting threads will unblock and
1488  * extract those items.
1489  * @note 2. Calling std::swap on AsyncQueueDispatch objects is thread
1490  * safe but does not provide a thread-wise atomic swap (the swapped
1491  * objects may not be mirror images if during the execution of
1492  * std::swap's default algorithm one of them has been modified),
1493  * although in many cases that doesn't matter. If swap() is called
1494  * without a namespace qualifier, argument dependent look-up will pick
1495  * this one correctly.
1496  *
1497  * Since 2.0.8
1498  */
1499 template <class T, class Container>
1502  q1.swap(q2);
1503 }
1504 
1505 #if defined(CGU_USE_INHERITABLE_QUEUE) && !defined(DOXYGEN_PARSING)
1506 
1507 /* This is a specialization of AsyncQueue for std::list objects, which
1508  uses std::list::splice() to push or emplace a new item on the
1509  queue. This means that allocation for the push or emplacement
1510  occurs outside the mutex, so reducing contention (a tip from a talk
1511  by Sean Parent of Adobe). This is first available in version
1512  2.0.20.
1513  */
1514 template <class T, class Allocator>
1515 class AsyncQueue<T, std::list<T, Allocator> > {
1516 public:
1517  typedef std::list<T, Allocator> Container;
1518  typedef typename Container::value_type value_type;
1519  typedef typename Container::size_type size_type;
1520  typedef Container container_type;
1521 private:
1522  // 23.6.3.1 of C++11 requires std::queue to have a protected
1523  // container member called 'c' for the purposes of derivation. This
1524  // specialisation will have the same binary layout as the
1525  // unspecialized version on any practical implementation: all we do
1526  // is add splice_end() and unsplice_beginning() members
1527  class Q: public std::queue<T, Container> {
1528  public:
1529  void splice_end(Container&& lst) {
1530  this->c.splice(this->c.end(), std::move(lst));
1531  }
1532  void unsplice_beginning(Container& lst) {
1533  lst.splice(lst.begin(), this->c, this->c.begin());
1534  }
1535  } q;
1536  mutable Thread::Mutex mutex;
1537 
1538 // TODO: at the next ABI break make this method explicitly static
1539  void lock2(Thread::Mutex& m1, Thread::Mutex& m2) {
1540  m1.lock();
1541  for(;;) {
1542  if (!m2.trylock()) {
1543  return;
1544  }
1545  m1.unlock();
1546  // spin nicely
1547 #ifdef CGU_USE_SCHED_YIELD
1548  sched_yield();
1549 #else
1550  usleep(10);
1551 #endif
1552  m1.lock();
1553  }
1554  }
1555 public:
1556  void push(const value_type& obj) {
1557  Container temp{obj};
1558  Thread::Mutex::Lock lock{mutex};
1559  // splice_end doesn't throw
1560  q.splice_end(std::move(temp));
1561  }
1562 
1563  void push(value_type&& obj) {
1564  // although move intialisation of a std::list object via an
1565  // initializer list with a single element is almost certain to be
1566  // strongly exception safe, it is not mandated by the standard so
1567  // use push_back() (which is required to be strongly exception
1568  // safe)
1569  Container temp;
1570  temp.push_back(std::move(obj));
1571  Thread::Mutex::Lock lock{mutex};
1572  // splice_end doesn't throw
1573  q.splice_end(std::move(temp));
1574  }
1575 
1576  template<class... Args>
1577  void emplace(Args&&... args) {
1578  Container temp;
1579  temp.emplace_back(std::forward<Args>(args)...);
1580  Thread::Mutex::Lock lock{mutex};
1581  // splice_end doesn't throw
1582  q.splice_end(std::move(temp));
1583  }
1584 
1585  void pop(value_type& obj) {
1586  Thread::Mutex::Lock lock{mutex};
1587  if (q.empty()) throw AsyncQueuePopError();
1588  obj = q.front();
1589  q.pop();
1590  }
1591 
1592  void move_pop(value_type& obj) {
1593  Thread::Mutex::Lock lock{mutex};
1594  if (q.empty()) throw AsyncQueuePopError();
1595  obj = std::move(q.front());
1596  q.pop();
1597  }
1598 
1599  void move_pop_basic(value_type& obj) {
1600  // the standard does not require it, but in practice constructing
1601  // an empty list will not throw unless constructing its allocator
1602  // throws
1603  Container temp;
1604  {
1605  Thread::Mutex::Lock lock{mutex};
1606  if (q.empty()) throw AsyncQueuePopError();
1607  // unsplice_beginning doesn't throw
1608  q.unsplice_beginning(temp);
1609  }
1610  obj = std::move(temp.front());
1611  }
1612 
1613  void pop() {
1614  Thread::Mutex::Lock lock{mutex};
1615  if (q.empty()) throw AsyncQueuePopError();
1616  q.pop();
1617  }
1618 
1619  bool empty() const {
1620  Thread::Mutex::Lock lock{mutex};
1621  return q.empty();
1622  }
1623 
1624  size_type size() const {
1625  Thread::Mutex::Lock lock{mutex};
1626  return q.size();
1627  }
1628 
1629  void swap(AsyncQueue& other) {
1630  if (this != &other) {
1631  lock2(mutex, other.mutex); // doesn't throw
1632  Thread::Mutex::Lock l1{mutex, Thread::locked};
1633  Thread::Mutex::Lock l2{other.mutex, Thread::locked};
1634  q.swap(other.q);
1635  }
1636  }
1637 
1638  AsyncQueue& operator=(const AsyncQueue& rhs) {
1639  if (this != &rhs) {
1640  lock2(mutex, rhs.mutex); // doesn't throw
1641  Thread::Mutex::Lock l1{mutex, Thread::locked};
1642  Thread::Mutex::Lock l2{rhs.mutex, Thread::locked};
1643  Q temp{rhs.q};
1644  q.swap(temp);
1645  }
1646  return *this;
1647  }
1648 
1649  AsyncQueue& operator=(AsyncQueue&& rhs) {
1650  Thread::Mutex::Lock lock{mutex};
1651  q = std::move(rhs.q);
1652  return *this;
1653  }
1654 
1655  AsyncQueue() = default;
1656 
1657  AsyncQueue(AsyncQueue&& rhs): q(std::move(rhs.q)) {}
1658 
1659  AsyncQueue(const AsyncQueue& rhs): q((Thread::Mutex::Lock(rhs.mutex), rhs.q)) {}
1660 
1661  ~AsyncQueue() {
1662  Thread::Mutex::Lock lock{mutex};
1663  }
1664 
1666 };
1667 
1668 /* This is a specialization of AsyncQueueDispatch for std::list
1669  objects, which uses std::list::splice() to push or emplace a new
1670  item on the queue. This means that allocation for the push or
1671  emplacement occurs outside the mutex, so reducing contention (a tip
1672  from a talk by Sean Parent of Adobe). This is first available in
1673  version 2.0.20.
1674  */
1675 template <class T, class Allocator>
1676 class AsyncQueueDispatch<T, std::list<T, Allocator> > {
1677 public:
1678  typedef std::list<T, Allocator> Container;
1679  typedef typename Container::value_type value_type;
1680  typedef typename Container::size_type size_type;
1681  typedef Container container_type;
1682 private:
1683  // 23.6.3.1 of C++11 requires std::queue to have a protected
1684  // container member called 'c' for the purposes of derivation. This
1685  // specialisation will have the same binary layout as the
1686  // unspecialized version on any practical implementation: all we do
1687  // is add splice_end() and unsplice_beginning() members
1688  class Q: public std::queue<T, Container> {
1689  public:
1690  void splice_end(Container&& lst) {
1691  this->c.splice(this->c.end(), std::move(lst));
1692  }
1693  void unsplice_beginning(Container& lst) {
1694  lst.splice(lst.begin(), this->c, this->c.begin());
1695  }
1696  } q;
1697  mutable Thread::Mutex mutex;
1698  Thread::Cond cond;
1699 
1700 // TODO: at the next ABI break make this method explicitly static
1701  void lock2(Thread::Mutex& m1, Thread::Mutex& m2) {
1702  m1.lock();
1703  for(;;) {
1704  if (!m2.trylock()) {
1705  return;
1706  }
1707  m1.unlock();
1708  // spin nicely
1709 #ifdef CGU_USE_SCHED_YIELD
1710  sched_yield();
1711 #else
1712  usleep(10);
1713 #endif
1714  m1.lock();
1715  }
1716  }
1717 public:
1718  void push(const value_type& obj) {
1719  Container temp{obj};
1720  Thread::Mutex::Lock lock{mutex};
1721  // splice_end doesn't throw
1722  q.splice_end(std::move(temp));
1723  cond.signal();
1724  }
1725 
1726  void push(value_type&& obj) {
1727  // although move intialisation of a std::list object via an
1728  // initializer list with a single element is almost certain to be
1729  // strongly exception safe, it is not mandated by the standard so
1730  // use push_back() (which is required to be strongly exception
1731  // safe)
1732  Container temp;
1733  temp.push_back(std::move(obj));
1734  Thread::Mutex::Lock lock{mutex};
1735  // splice_end doesn't throw
1736  q.splice_end(std::move(temp));
1737  cond.signal();
1738  }
1739 
1740  template<class... Args>
1741  void emplace(Args&&... args) {
1742  Container temp;
1743  temp.emplace_back(std::forward<Args>(args)...);
1744  Thread::Mutex::Lock lock{mutex};
1745  // splice_end doesn't throw
1746  q.splice_end(std::move(temp));
1747  cond.signal();
1748  }
1749 
1750  void pop(value_type& obj) {
1751  Thread::Mutex::Lock lock{mutex};
1752  if (q.empty()) throw AsyncQueuePopError();
1753  obj = q.front();
1754  q.pop();
1755  }
1756 
1757  void move_pop(value_type& obj) {
1758  Thread::Mutex::Lock lock{mutex};
1759  if (q.empty()) throw AsyncQueuePopError();
1760  obj = std::move(q.front());
1761  q.pop();
1762  }
1763 
1764  void move_pop_basic(value_type& obj) {
1765  // the standard does not require it, but in practice constructing
1766  // an empty list will not throw unless constructing its allocator
1767  // throws
1768  Container temp;
1769  {
1770  Thread::Mutex::Lock lock{mutex};
1771  if (q.empty()) throw AsyncQueuePopError();
1772  // unsplice_beginning doesn't throw
1773  q.unsplice_beginning(temp);
1774  }
1775  obj = std::move(temp.front());
1776  }
1777 
1778  void pop_dispatch(value_type& obj) {
1779  Thread::Mutex::Lock lock{mutex};
1780  while (q.empty()) cond.wait(mutex);
1781  Thread::CancelBlock b;
1782  obj = q.front();
1783  q.pop();
1784  }
1785 
1786  void move_pop_dispatch(value_type& obj) {
1787  Thread::Mutex::Lock lock{mutex};
1788  while (q.empty()) cond.wait(mutex);
1789  Thread::CancelBlock b;
1790  obj = std::move(q.front());
1791  q.pop();
1792  }
1793 
1794  void move_pop_dispatch_basic(value_type& obj) {
1795  int old_state;
1796  int ignore;
1797  bool cancelstate_restored = false;
1798  try {
1799  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
1800  // the standard does not require it, but in practice
1801  // constructing an empty list will not throw unless constructing
1802  // its allocator throws
1803  Container temp;
1804  pthread_setcancelstate(old_state, &ignore);
1805  cancelstate_restored = true;
1806  Thread::Mutex::TrackLock lock{mutex};
1807  while (q.empty()) cond.wait(mutex);
1808  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ignore);
1809  cancelstate_restored = false;
1810  // unsplice_beginning doesn't throw
1811  q.unsplice_beginning(temp);
1812  lock.unlock();
1813  obj = std::move(temp.front());
1814  pthread_setcancelstate(old_state, &ignore);
1815  }
1816  catch (...) {
1817  // in practice we could only enter here with
1818  // cancelstate_restored set as true if there has been a
1819  // cancellation pseudo-exception (but the code doesn't depend on
1820  // that). We could only enter here with a normal exception if
1821  // the construction of temp has thrown or if a queue element's
1822  // move/copy assignment operator has thrown (but again the code
1823  // doesn't depend on that).
1824  if (!cancelstate_restored) {
1825  pthread_setcancelstate(old_state, &ignore);
1826  }
1827  throw;
1828  }
1829  }
1830 
1831  bool pop_timed_dispatch(value_type& obj, unsigned int millisec) {
1832  timespec ts;
1833  Thread::Cond::get_abs_time(ts, millisec);
1834  Thread::Mutex::Lock lock{mutex};
1835  while (q.empty()) {
1836  if (cond.timed_wait(mutex, ts)) return true;
1837  }
1838  Thread::CancelBlock b;
1839  obj = q.front();
1840  q.pop();
1841  return false;
1842  }
1843 
1844  bool move_pop_timed_dispatch(value_type& obj, unsigned int millisec) {
1845  timespec ts;
1846  Thread::Cond::get_abs_time(ts, millisec);
1847  Thread::Mutex::Lock lock{mutex};
1848  while (q.empty()) {
1849  if (cond.timed_wait(mutex, ts)) return true;
1850  }
1851  Thread::CancelBlock b;
1852  obj = std::move(q.front());
1853  q.pop();
1854  return false;
1855  }
1856 
1857  bool move_pop_timed_dispatch_basic(value_type& obj, unsigned int millisec) {
1858  timespec ts;
1859  Thread::Cond::get_abs_time(ts, millisec);
1860  int old_state;
1861  int ignore;
1862  bool cancelstate_restored = false;
1863  try {
1864  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
1865  // the standard does not require it, but in practice
1866  // constructing an empty list will not throw unless constructing
1867  // its allocator throws
1868  Container temp;
1869  pthread_setcancelstate(old_state, &ignore);
1870  cancelstate_restored = true;
1871  Thread::Mutex::TrackLock lock{mutex};
1872  while (q.empty()) {
1873  if (cond.timed_wait(mutex, ts)) return true;
1874  }
1875  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &ignore);
1876  cancelstate_restored = false;
1877  // unsplice_beginning doesn't throw
1878  q.unsplice_beginning(temp);
1879  lock.unlock();
1880  obj = std::move(temp.front());
1881  pthread_setcancelstate(old_state, &ignore);
1882  return false;
1883  }
1884  catch (...) {
1885  // in practice we could only enter here with
1886  // cancelstate_restored set as true if there has been a
1887  // cancellation pseudo-exception (but the code doesn't depend on
1888  // that). We could only enter here with a normal exception if
1889  // the construction of temp has thrown or if a queue element's
1890  // move/copy assignment operator has thrown (but again the code
1891  // doesn't depend on that).
1892  if (!cancelstate_restored) {
1893  pthread_setcancelstate(old_state, &ignore);
1894  }
1895  throw;
1896  }
1897  }
1898 
1899  void pop() {
1900  Thread::Mutex::Lock lock{mutex};
1901  if (q.empty()) throw AsyncQueuePopError();
1902  q.pop();
1903  }
1904 
1905  bool empty() const {
1906  Thread::Mutex::Lock lock{mutex};
1907  return q.empty();
1908  }
1909 
1910  size_type size() const {
1911  Thread::Mutex::Lock lock{mutex};
1912  return q.size();
1913  }
1914 
1915  void swap(AsyncQueueDispatch& other) {
1916  if (this != &other) {
1917  lock2(mutex, other.mutex); // doesn't throw
1918  Thread::Mutex::Lock l1{mutex, Thread::locked};
1919  Thread::Mutex::Lock l2{other.mutex, Thread::locked};
1920  q.swap(other.q);
1921  if (!q.empty()) cond.broadcast();
1922  if (!other.q.empty()) other.cond.broadcast();
1923  }
1924  }
1925 
1927  if (this != &rhs) {
1928  lock2(mutex, rhs.mutex); // doesn't throw
1929  Thread::Mutex::Lock l1{mutex, Thread::locked};
1930  Thread::Mutex::Lock l2{rhs.mutex, Thread::locked};
1931  Q temp{rhs.q};
1932  q.swap(temp);
1933  if (!q.empty()) cond.broadcast();
1934  }
1935  return *this;
1936  }
1937 
1939  Thread::Mutex::Lock lock{mutex};
1940  q = std::move(rhs.q);
1941  if (!q.empty()) cond.broadcast();
1942  return *this;
1943  }
1944 
1945  AsyncQueueDispatch() = default;
1946 
1947  AsyncQueueDispatch(AsyncQueueDispatch&& rhs): q(std::move(rhs.q)) {}
1948 
1950  q((Thread::Mutex::Lock(rhs.mutex), rhs.q)) {}
1951 
1953  Thread::Mutex::Lock lock{mutex};
1954  }
1955 
1957 };
1958 
1959 #endif // CGU_USE_INHERITABLE_QUEUE
1960 
1961 } // namespace Cgu
1962 
1963 #endif
int broadcast()
Definition: mutex.h:483
void push(value_type &&obj)
Definition: async_queue.h:217
void pop(value_type &obj)
Definition: async_queue.h:771
void pop()
Definition: async_queue.h:391
size_type size() const
Definition: async_queue.h:1224
void swap(Cgu::AsyncQueue< T, Container > &q1, Cgu::AsyncQueue< T, Container > &q2)
Definition: async_queue.h:1471
~AsyncQueueDispatch()
Definition: async_queue.h:1440
STL namespace.
Container::size_type size_type
Definition: async_queue.h:150
int signal()
Definition: mutex.h:472
void emplace(Args &&...args)
Definition: async_queue.h:744
void pop_dispatch(value_type &obj)
Definition: async_queue.h:901
void move_pop(value_type &obj)
Definition: async_queue.h:314
A wrapper class for pthread condition variables.
Definition: mutex.h:449
AsyncQueue(const AsyncQueue &rhs)
Definition: async_queue.h:584
AsyncQueue()=default
An exception thrown if calling pop() on a AsyncQueue or AsyncQueueDispatch object fails because the q...
Definition: async_queue.h:102
void move_pop_basic(value_type &obj)
Definition: async_queue.h:874
A thread-safe asynchronous queue.
Definition: async_queue.h:147
A thread-safe asynchronous queue with a blocking pop() method.
Definition: async_queue.h:642
void pop()
Definition: async_queue.h:1191
Definition: mutex.h:196
static void get_abs_time(timespec &ts, unsigned int millisec)
void push(value_type &&obj)
Definition: async_queue.h:714
A class enabling the cancellation state of a thread to be controlled.
Definition: thread.h:686
bool move_pop_timed_dispatch(value_type &obj, unsigned int millisec)
Definition: async_queue.h:1099
A scoped locking class for exception safe Mutex locking.
Definition: mutex.h:207
bool move_pop_timed_dispatch_basic(value_type &obj, unsigned int millisec)
Definition: async_queue.h:1175
void move_pop_dispatch_basic(value_type &obj)
Definition: async_queue.h:1012
void move_pop_basic(value_type &obj)
Definition: async_queue.h:375
AsyncQueueDispatch & operator=(AsyncQueueDispatch &&rhs)
Definition: async_queue.h:1332
~AsyncQueue()
Definition: async_queue.h:591
AsyncQueueDispatch(AsyncQueueDispatch &&rhs)
Definition: async_queue.h:1400
virtual const char * what() const
Definition: async_queue.h:103
void push(const value_type &obj)
Definition: async_queue.h:194
int timed_wait(Mutex &mutex, const timespec &abs_time)
Definition: mutex.h:558
AsyncQueue(AsyncQueue &&rhs)
Definition: async_queue.h:559
A wrapper class for pthread mutexes.
Definition: mutex.h:117
void move_pop_dispatch(value_type &obj)
Definition: async_queue.h:946
int unlock()
Definition: mutex.h:170
void pop(value_type &obj)
Definition: async_queue.h:272
AsyncQueue & operator=(AsyncQueue &&rhs)
Definition: async_queue.h:506
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
bool empty() const
Definition: async_queue.h:407
size_type size() const
Definition: async_queue.h:424
Definition: application.h:44
void push(const value_type &obj)
Definition: async_queue.h:690
Container::value_type value_type
Definition: async_queue.h:149
bool pop_timed_dispatch(value_type &obj, unsigned int millisec)
Definition: async_queue.h:1044
AsyncQueueDispatch(const AsyncQueueDispatch &rhs)
Definition: async_queue.h:1430
int trylock()
Definition: mutex.h:157
bool empty() const
Definition: async_queue.h:1207
void move_pop(value_type &obj)
Definition: async_queue.h:813
Container::value_type value_type
Definition: async_queue.h:644
void emplace(Args &&...args)
Definition: async_queue.h:246
AsyncQueueDispatch & operator=(const AsyncQueueDispatch &rhs)
Definition: async_queue.h:1290
void swap(AsyncQueue &other)
Definition: async_queue.h:441
int lock()
Definition: mutex.h:147
Container container_type
Definition: async_queue.h:646
AsyncQueue & operator=(const AsyncQueue &rhs)
Definition: async_queue.h:472
Container container_type
Definition: async_queue.h:151
void swap(AsyncQueueDispatch &other)
Definition: async_queue.h:1246
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Container::size_type size_type
Definition: async_queue.h:645
int wait(Mutex &mutex)
Definition: mutex.h:508