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