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