c++-gtk-utils: async_queue.h Source File

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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>
85 #include <c++-gtk-utils/cgu_config.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
441 Thread::Mutex::Lock l1{mutex, Thread::locked};
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 */
469 AsyncQueue& operator=(const AsyncQueue& rhs) {
470 if (this != &rhs) {
471 lock2(mutex, rhs.mutex); // doesn't throw
472 Thread::Mutex::Lock l1{mutex, Thread::locked};
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 */
503 AsyncQueue& operator=(AsyncQueue&& rhs) {
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 */
578 ~AsyncQueue() {
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 */
588 CGU_GLIB_MEMORY_SLICES_FUNCS
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);
887 Thread::CancelBlock b;
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);
932 Thread::CancelBlock b;
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 }
1033 Thread::CancelBlock b;
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 }
1088 Thread::CancelBlock b;
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
1231 Thread::Mutex::Lock l1{mutex, Thread::locked};
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 */
1272 AsyncQueueDispatch& operator=(const AsyncQueueDispatch& rhs) {
1273 if (this != &rhs) {
1274 lock2(mutex, rhs.mutex); // doesn't throw
1275 Thread::Mutex::Lock l1{mutex, Thread::locked};
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 */
1314 AsyncQueueDispatch& operator=(AsyncQueueDispatch&& rhs) {
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
1401 AsyncQueueDispatch(const AsyncQueueDispatch& rhs):
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 */
1411 ~AsyncQueueDispatch() {
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 */
1421 CGU_GLIB_MEMORY_SLICES_FUNCS
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>
1442 void swap(Cgu::AsyncQueue<T, Container>& q1,
1443 Cgu::AsyncQueue<T, Container>& q2) {
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>
1471 void swap(Cgu::AsyncQueueDispatch<T, Container>& q1,
1472 Cgu::AsyncQueueDispatch<T, Container>& q2) {
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
1636 CGU_GLIB_MEMORY_SLICES_FUNCS
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
1897 AsyncQueueDispatch& operator=(const AsyncQueueDispatch& rhs) {
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
1909 AsyncQueueDispatch& operator=(AsyncQueueDispatch&& rhs) {
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
1920 AsyncQueueDispatch(const AsyncQueueDispatch& rhs):
1921 q((Thread::Mutex::Lock(rhs.mutex), rhs.q)) {}
1922
1923 ~AsyncQueueDispatch() {
1924 Thread::Mutex::Lock lock{mutex};
1925 }
1926
1927 CGU_GLIB_MEMORY_SLICES_FUNCS
1928 };
1929
1930 #endif // CGU_USE_INHERITABLE_QUEUE
1931
1932 } // namespace Cgu
1933
1934 #endif