c++-gtk-utils
task_manager.h
Go to the documentation of this file.
1 /* Copyright (C) 2012 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 */
24 
25 #ifndef CGU_TASK_MANAGER_H
26 #define CGU_TASK_MANAGER_H
27 
28 #include <deque>
29 #include <utility> // for std::pair and std::move
30 #include <exception> // for std::exception
31 #include <memory> // for std::unique_ptr
32 
33 #include <c++-gtk-utils/callback.h>
34 #include <c++-gtk-utils/thread.h>
35 #include <c++-gtk-utils/mutex.h>
38 
39 namespace Cgu {
40 
41 namespace Thread {
42 
43 struct TaskError: public std::exception {
44  virtual const char* what() const throw() {return "TaskError\n";}
45 };
46 
47 /**
48  * @class Cgu::Thread::TaskManager task_manager.h c++-gtk-utils/task_manager.h
49  * @brief A thread-pool class for managing tasks in multi-threaded programs.
50  * @sa Cgu::Thread::Future Cgu::AsyncResult Cgu::AsyncQueueDispatch Cgu::Callback::post()
51  *
52  * Cgu::Thread::Future operates on the principle of there being one
53  * worker thread per task. In some cases however, it may be better to
54  * have a limited pool of worker threads executing a larger number of
55  * tasks. This class implements this approach via a thread pool.
56  *
57  * One common approach for thread pools of this kind is to set the
58  * maximum number of threads to the number of cores, or one less than
59  * the number of cores, available on the local machine. How that can
60  * be determined is system specific (on linux it can be obtained by,
61  * for example, inspecting the 'siblings' and 'cpu cores' fields in
62  * /proc/cpuinfo or by using sysconf with the glibc extension for
63  * _SC_NPROCESSORS_ONLN).
64  *
65  * Where the task needs to provide a result, two approaches can be
66  * adopted. First, the task callback can have a Cgu::AsyncResult
67  * object held by Cgu::SharedLockPtr (or by std::shared_ptr having a
68  * thread safe reference count) bound to it. Alternatively, a task
69  * can provide a result asynchronously to a glib main loop by calling
70  * Cgu::Callback::post() when it is ready to do so. In addition,
71  * tasks can add other tasks, enabling the composition of an arbitrary
72  * number of tasks to obtain a final result.
73  *
74  * TaskManager objects do not provide thread cancellation. Thread
75  * cancellation is incompatible with the task-centred thread pool
76  * model. If task cancellation is wanted, use a Cgu::Thread::Future
77  * (or Cgu::Thread::Thread or Cgu::Thread::JoinableHandle) object
78  * instead, and have a dedicated thread for the cancelable task.
79  *
80  * If glib < 2.32 is installed, g_thread_init() must be called before
81  * any TaskManager objects are constructed, which in turn means that
82  * with glib < 2.32 TaskManager objects may not be constructed as
83  * static objects in global namespace (that is, before g_thread_init()
84  * has been called in the program).
85  *
86  * Any exceptions which propagate from a task will be consumed to
87  * protect the TaskManager object, and to detect whether this has
88  * happened there is a version of the TaskManager::add_task() method
89  * which takes a second argument comprising a 'fail' callback. If an
90  * exception propagates from the 'fail' callback that is also consumed
91  * and a g_critical() message issued.
92  *
93  * Tasks can be aborted by throwing Cgu::Thread::Exit (as well as any
94  * other exception). Where a thread is managed by a TaskManager
95  * object, throwing Cgu::Thread::Exit will only terminate the task and
96  * not the thread on which it is running (and will cause the 'fail'
97  * callback to be executed, if there is one).
98  *
99  * TaskManager objects have no copy constructor or copy assignment
100  * operator, as copying them would have no obvious semantic meaning.
101  * Whilst swapping or moving TaskManager objects would be meaningful,
102  * this is not implemented either because it would require an
103  * additional internal lock to be thread safe, and the circumstances
104  * in which moving or swapping would be useful are limited. Where a
105  * move option is wanted, a TaskManager object can be constructed on
106  * free store and held by std::unique_ptr.
107  *
108  * Here is a compilable example of the calculator class referred to in
109  * the documentation on the AsyncResult but which uses a TaskManager
110  * object so that the calculator class can run more than one thread to
111  * service its calculations:
112  *
113  * @code
114  * #include <vector>
115  * #include <numeric>
116  * #include <ostream>
117  * #include <iostream>
118  *
119  * #include <glib.h>
120  *
121  * #include <c++-gtk-utils/task_manager.h>
122  * #include <c++-gtk-utils/async_result.h>
123  * #include <c++-gtk-utils/shared_ptr.h>
124  * #include <c++-gtk-utils/callback.h>
125  *
126  * using namespace Cgu;
127  *
128  * class Calcs {
129  * Thread::TaskManager tm;
130  * public:
131  * SharedLockPtr<AsyncResult<double>> mean(const std::vector<double>& nums) {
132  * SharedLockPtr<AsyncResult<double>> res(new AsyncResult<double>);
133  * tm.add_task(Callback::lambda<>([=]() {
134  * if (nums.empty()) res->set(0.0);
135  * else res->set(std::accumulate(nums.begin(), nums.end(), 0.0)/nums.size());
136  * }));
137  * return res;
138  * }
139  *
140  * // ... other calculation methods here
141  * };
142  *
143  * int main () {
144  *
145  * g_thread_init(0);
146  * Calcs calcs;
147  * auto res1 = calcs.mean(std::vector<double>({1, 2, 8, 0}));
148  * auto res2 = calcs.mean(std::vector<double>({101, 53.7, 87, 1.2}));
149  *
150  * // ... do something else
151  * std::cout << res1->get() << std::endl;
152  * std::cout << res2->get() << std::endl;
153  *
154  * }
155  * @endcode
156  */
157 
158 class TaskManager {
159  public:
161  private:
162  typedef std::pair<std::unique_ptr<const Callback::Callback>,
163  std::unique_ptr<const Callback::Callback>> QueueItemType;
164 
165  struct RefImpl; // reference counted implementation class
166 
167  // it is fine holding RefImpl by plain pointer and not by
168  // IntrusivePtr: it is the only data member this class has, so it
169  // can safely manage that member in its own destructor and other
170  // methods
171  RefImpl* ref_impl;
172 
173  public:
174 /**
175  * This class cannot be copied. The copy constructor is deleted.
176  */
177  TaskManager(const TaskManager&) = delete;
178 
179 /**
180  * This class cannot be copied. The assignment operator is deleted.
181  */
182  TaskManager& operator=(const TaskManager&) = delete;
183 
184  /**
185  * Gets the maximum number of threads which the TaskManager object is
186  * currently set to run in the thread pool. This value is established
187  * initially by the 'max' argument passed to the TaskManager
188  * constructor and can subequently be changed by calling
189  * set_max_threads(). The default value is 8. This method will not
190  * throw and is thread safe.
191  * @return The maximum number of threads.
192  *
193  * Since 2.0.12
194  */
195  unsigned int get_max_threads() const;
196 
197  /**
198  * Gets the minimum number of threads which the TaskManager object
199  * will run in the thread pool (these threads will last until
200  * stop_all() is called or the TaskManager object is destroyed).
201  * This value is established by the 'min' argument passed to the
202  * TaskManager constructor and cannot subequently be changed. The
203  * default is 0. This method will not throw and is thread safe.
204  * @return The minimum number of threads.
205  *
206  * Since 2.0.12
207  */
208  unsigned int get_min_threads() const;
209 
210  /**
211  * Gets the number of threads which the TaskManager object is
212  * currently running in the thread pool. This value could be greater
213  * than the number returned by get_max_threads() if set_max_threads()
214  * has recently been called with a value which is less than that
215  * number but not enough tasks have since completed to reduce the
216  * number of running threads to the new value set. This method will
217  * not throw and is thread safe.
218  * @return The number of threads running.
219  *
220  * Since 2.0.12
221  */
222  unsigned int get_used_threads() const;
223 
224  /**
225  * Gets the number of tasks which the TaskManager object is at
226  * present either running in the thread pool or has queued for
227  * execution. This value will be less than the number returned by
228  * get_used_threads() if threads in the thread pool are currently
229  * waiting to receive tasks for execution. This method will not
230  * throw and is thread safe.
231  * @return The number of threads running.
232  *
233  * Since 2.0.12
234  */
235  unsigned int get_tasks() const;
236 
237  /**
238  * Sets the maximum number of threads which the TaskManager object
239  * will currently run in the thread pool. If this is less than the
240  * current number of running threads, the number of threads actually
241  * running will only be reduced as tasks complete, or as idle
242  * timeouts expire. This method does nothing if stop_all() has
243  * previously been called. This method is thread safe.
244  * @param max The maximum number of threads which the TaskManager
245  * object will currently run in the thread pool. This method will
246  * not set the maximum value of threads to a value less than that
247  * returned by get_min_threads().
248  * @exception std::bad_alloc If this call is passed a value for 'max'
249  * which increases the maximum number of threads from its previous
250  * setting and tasks are currently queued for execution, new threads
251  * will be started for the queued tasks, so this exception may be
252  * thrown on starting the new threads if memory is exhausted and the
253  * system throws in that case. (On systems with
254  * over-commit/lazy-commit combined with virtual memory (swap), it is
255  * rarely useful to check for memory exhaustion).
256  * @exception Cgu::Thread::TaskError If this call is passed a value
257  * for 'max' which increases the maximum number of threads from its
258  * previous setting and tasks are currently queued for execution, new
259  * threads will be started for the queued tasks, so this exception
260  * may be thrown on starting the new threads if a thread fails to
261  * start correctly (this would mean that memory is exhausted, the
262  * pthread thread limit has been reached or pthread has run out of
263  * other resources to start new threads).
264  *
265  * Since 2.0.12
266  */
267  void set_max_threads(unsigned int max);
268 
269  /**
270  * Gets the length of time in milliseconds that threads greater in
271  * number than the minimum and not executing any tasks will remain in
272  * existence waiting for new tasks. This value is established
273  * initially by the 'idle' argument passed to the TaskManager
274  * constructor and can subequently be changed by calling
275  * set_idle_time(). The default value is 10000 (10 seconds). This
276  * method will not throw and is thread safe.
277  * @return The idle time in milliseconds.
278  *
279  * Since 2.0.12
280  */
281  unsigned int get_idle_time() const;
282 
283  /**
284  * Sets the length of time in milliseconds that threads greater in
285  * number than the minimum and not executing any tasks will remain in
286  * existence waiting for new tasks. This will only have effect for
287  * threads in the pool which begin waiting for new tasks after this
288  * method is called. This method will not throw and is thread safe.
289  * @param idle The length of the idle time in milliseconds during
290  * which threads will remain waiting for new tasks.
291  *
292  * Since 2.0.12
293  */
294  void set_idle_time(unsigned int idle);
295 
296  /**
297  * Gets the current blocking setting, which determines whether calls
298  * to stop_all() and the destructor will block waiting for all
299  * remaining tasks to complete. This value is established initially
300  * by the 'blocking' argument passed to the TaskManager constructor
301  * and can subequently be changed by calling set_blocking(). This
302  * method will not throw and is thread safe.
303  * @return The current blocking setting.
304  *
305  * Since 2.0.12
306  */
307  bool get_blocking() const;
308 
309  /**
310  * Sets the current blocking setting, which determines whether calls
311  * to stop_all() and the destructor will block waiting for all
312  * remaining tasks to complete. This method cannot be called after
313  * stop_all() has been called (if that is attempted,
314  * Cgu::Thread::TaskError will be thrown). It is thread safe.
315  * @param blocking The new blocking setting.
316  * @exception Cgu::Thread::TaskError This exception will be thrown if
317  * stop_all() has previously been called.
318  *
319  * Since 2.0.12
320  */
321  void set_blocking(bool blocking);
322 
323  /**
324  * Gets the current StopMode setting (either
325  * Cgu::Thread::TaskManager::wait_for_running or
326  * Cgu::Thread::TaskManager::wait_for_all) executed when running
327  * stop_all() or when the destructor is called. See the
328  * documentation on stop_all() for an explanation of the setting.
329  * This value is established initially by the 'mode' argument passed
330  * to the TaskManager constructor and can subequently be changed by
331  * calling set_stop_mode(). This method will not throw and is thread
332  * safe.
333  * @return The current StopMode setting.
334  *
335  * Since 2.0.12
336  */
337  StopMode get_stop_mode() const;
338 
339  /**
340  * Sets the current StopMode setting (either
341  * Cgu::Thread::TaskManager::wait_for_running or
342  * Cgu::Thread::TaskManager::wait_for_all) executed when running
343  * stop_all() or when the destructor is called. See the
344  * documentation on stop_all() for an explanation of the setting.
345  * This method will not throw and is thread safe.
346  * @param mode The new StopMode setting.
347  *
348  * Since 2.0.12
349  */
350  void set_stop_mode(StopMode mode);
351 
352  /**
353  * This will cause the TaskManager object to stop running tasks. The
354  * precise effect depends on the current StopMode and blocking
355  * settings. If StopMode is set to
356  * Cgu::Thread::TaskManager::wait_for_running, all queued tasks which
357  * are not yet running on a thread will be dispensed with, but any
358  * already running will be left to complete normally. If StopMode is
359  * set to Cgu::Thread::TaskManager::wait_for_all, both already
360  * running tasks and all tasks already queued will be permitted to
361  * execute and complete normally. If the blocking setting is set to
362  * true, this method will wait until all the tasks still to execute
363  * have finished before returning, and if false it will return
364  * straight away.
365  *
366  * After this method has been called, any attempt to add further
367  * tasks with the add_task() method will fail, and add_task() will
368  * throw Cgu::Thread::TaskError.
369  *
370  * This method is thread safe (any thread may call it) unless the
371  * blocking setting is true, in which case no task running on the
372  * TaskManager object may call this method.
373  * @exception std::bad_alloc This exception will be thrown if memory
374  * is exhausted and the system throws in that case. (On systems with
375  * over-commit/lazy-commit combined with virtual memory (swap), it is
376  * rarely useful to check for memory exhaustion).
377  * @exception Cgu::Thread::TaskError This exception will be thrown if
378  * stop_all() has previously been called, unless that previous call
379  * threw std::bad_alloc: if std::bad_alloc is thrown, this method may
380  * be called again to stop all threads, once the memory deficiency is
381  * dealt with, but no other methods of the TaskManager object should
382  * be called.
383  *
384  * Since 2.0.12
385  */
386  void stop_all();
387 
388  /**
389  * This method adds a new task. If one or more threads in the pool
390  * are currently blocking and waiting for a task, then the task will
391  * begin executing immediately in one of the threads. If not, and
392  * the value returned by get_used_threads() is less than the value
393  * returned by get_max_threads(), a new thread will start and the
394  * task will execute immediately in the new thread. Otherwise, the
395  * task will be queued for execution as soon as a thread becomes
396  * available. Tasks will be executed in the order in which they are
397  * added to the ThreadManager object. This method is thread safe
398  * (any thread may call it, including any task running on the
399  * TaskManager object).
400  *
401  * A task may terminate itself prematurely by throwing
402  * Cgu::Thread::Exit. In addition, the implementation of TaskManager
403  * will consume any other exception escaping from the task callback
404  * and safely terminate the task concerned in order to protect the
405  * integrity of the TaskManager object. Where detecting any of these
406  * outcomes is important (usually it won't be), the two argument
407  * version of this method is available so that a 'fail' callback can
408  * be executed in these circumstances.
409  *
410  * @param task A callback representing the new task, as constructed
411  * by the Callback::make(), Callback::make_ref() or
412  * Callback::lambda() factory functions. Ownership is taken of this
413  * callback, and it will be disposed of when it has been finished
414  * with. The destructors of any bound arguments in the callback must
415  * not throw.
416  * @exception std::bad_alloc This exception will be thrown if memory
417  * is exhausted and the sytem throws in that case. (On systems with
418  * over-commit/lazy-commit combined with virtual memory (swap), it is
419  * rarely useful to check for memory exhaustion). If this exception
420  * is thrown, the 'task' callback will be disposed of.
421  * @exception Cgu::Thread::TaskError This exception will be thrown if
422  * stop_all() has previously been called. It will also be thrown if
423  * is_error() would return true because this class's internal thread
424  * pool loop implementation has thrown std::bad_alloc, or a thread
425  * has failed to start correctly. (On systems with
426  * over-commit/lazy-commit combined with virtual memory (swap), it is
427  * rarely useful to check for memory exhaustion, but there may be
428  * some specialized cases where the return value of is_error() is
429  * useful.) If this exception is thrown, the 'task' callback will be
430  * disposed of.
431  *
432  * Since 2.0.12
433  */
434  void add_task(const Callback::Callback* task) {
435 #ifdef CGU_USE_AUTO_PTR
436  add_task(std::auto_ptr<const Callback::Callback>(task),
437  std::auto_ptr<const Callback::Callback>());
438 #else
439  add_task(std::unique_ptr<const Callback::Callback>(task),
440  std::unique_ptr<const Callback::Callback>());
441 #endif
442  }
443 
444  /**
445  * This method adds a new task. If one or more threads in the pool
446  * are currently blocking and waiting for a task, then the task will
447  * begin executing immediately in one of the threads. If not, and
448  * the value returned by get_used_threads() is less than the value
449  * returned by get_max_threads(), a new thread will start and the
450  * task will execute immediately in the new thread. Otherwise, the
451  * task will be queued for execution as soon as a thread becomes
452  * available. Tasks will be executed in the order in which they are
453  * added to the ThreadManager object. This method is thread safe
454  * (any thread may call it, including any task running on the
455  * TaskManager object).
456  *
457  * A task may terminate itself prematurely by throwing
458  * Cgu::Thread::Exit. In addition, the implementation of TaskManager
459  * will consume any other exception escaping from the task callback
460  * and safely terminate the task concerned in order to protect the
461  * integrity of the TaskManager object. Where detecting any of these
462  * outcomes is important (usually it won't be), a callback can be
463  * passed to the 'fail' argument which will execute if, and only if,
464  * either Cgu::Thread::Exit is thrown or some other exception has
465  * propagated from the task. This 'fail' callback is different from
466  * the 'fail' callback of Cgu::Thread::Future objects (programming
467  * for many tasks to a lesser number of threads requires different
468  * approaches from programming for one thread per task), and it
469  * executes in the task thread rather than executing in a glib main
470  * loop (however, the 'fail' callback can of course call
471  * Cgu::Callback::post() to execute another callback in a main loop,
472  * if that is what is wanted).
473  *
474  * @param task A callback representing the new task, as constructed
475  * by the Callback::make(), Callback::make_ref() or
476  * Callback::lambda() factory functions.
477  * @param fail A callback which will be executed if the function
478  * executed by the 'task' callback exits by throwing Thread::Exit or
479  * some other exception. If an exception propagates from the
480  * function represented by this callback, this will be consumed to
481  * protect the TaskManager object, and a g_critical() warning will be
482  * issued.
483  * @exception std::bad_alloc This exception will be thrown if memory
484  * is exhausted and the sytem throws in that case. (On systems with
485  * over-commit/lazy-commit combined with virtual memory (swap), it is
486  * rarely useful to check for memory exhaustion).
487  * @exception Cgu::Thread::TaskError This exception will be thrown if
488  * stop_all() has previously been called. It will also be thrown if
489  * is_error() would return true because this class's internal thread
490  * pool loop implementation has thrown std::bad_alloc, or a thread
491  * has failed to start correctly. (On systems with
492  * over-commit/lazy-commit combined with virtual memory (swap), it is
493  * rarely useful to check for memory exhaustion, but there may be
494  * some specialized cases where the return value of is_error() is
495  * useful.)
496  * @note 1. Question: why does the single argument version of
497  * add_task() take a pointer, and this version take the callbacks by
498  * std::unique_ptr? Answer: The two argument version of add_task()
499  * takes its arguments by std::unique_ptr in order to be exception
500  * safe if the first callback to be constructed is constructed
501  * correctly but construction of the second callback object throws.
502  * @note 2. If the library is compiled using the --with-auto-ptr
503  * configuration option, then this method's signature is
504  * add_task(std::auto_ptr<const Callback::Callback>,
505  * std::auto_ptr<const Callback::Callback>) in order to retain
506  * compatibility with the 1.2 series of the library
507  *
508  * Since 2.0.12
509  */
510 #ifdef CGU_USE_AUTO_PTR
511  void add_task(std::auto_ptr<const Callback::Callback> task,
512  std::auto_ptr<const Callback::Callback> fail);
513 #else
514  void add_task(std::unique_ptr<const Callback::Callback> task,
515  std::unique_ptr<const Callback::Callback> fail);
516 #endif
517 
518  /**
519  * This will return true if a thread required by the thread pool has
520  * failed to start correctly because of memory exhaustion or because
521  * pthread has run out of other resources to start new threads, or
522  * because an internal operation has thrown std::bad_alloc. (On
523  * systems with over-commit/lazy-commit combined with virtual memory
524  * (swap), it is rarely useful to check for memory exhaustion, and
525  * even more so where glib is used, as that terminates a program if
526  * memory cannot be obtained from the operating system, but there may
527  * be some specialized cases where the return value of this method is
528  * useful - this class does not use any glib functions which might
529  * cause such termination.) This method will not throw and is thread
530  * safe.
531  *
532  * Since 2.0.12
533  */
534  bool is_error() const;
535 
536  /**
537  * If the specified minimum number of threads is greater than 0, this
538  * constructor will start the required minimum number of threads. If
539  * glib < 2.32 is installed, g_thread_init() must be called before
540  * any TaskManager objects are constructed
541  * @param max The maximum number of threads which the TaskManager
542  * object will run in the thread pool. If the value passed as this
543  * argument is less than the value passed as 'min', the maximum
544  * number of threads will be set to 'min'. A value of 0 is not
545  * valid, and if this is passed the number will be set to the greater
546  * of 1 and 'min'.
547  * @param min The minimum number of threads which the TaskManager
548  * object will run in the thread pool.
549  * @param idle The length of time in milliseconds that threads
550  * greater in number than 'min' and not executing any tasks will
551  * remain in existence. The default is 10000 (10 seconds).
552  * @param blocking If true, calls to stop_all() and the destructor
553  * will not return until the tasks remaining to be executed have
554  * finished (what is mean by "the tasks remaining to be executed"
555  * depends on the StopMode setting, for which see the documentation
556  * on the stop_all() method). If false, stop_all() and the
557  * destructor will return straight away (which in terms of the
558  * TaskManager class implementation is safe for the reasons explained
559  * in the documentation on the destructor).
560  * @param mode The StopMode setting (either
561  * Cgu::Thread::TaskManager::wait_for_running or
562  * Cgu::Thread::TaskManager::wait_for_all) executed when running
563  * stop_all() or when the destructor is called. See the
564  * documentation on stop_all() for an explanation of the setting.
565  * @exception std::bad_alloc This exception might be thrown if memory
566  * is exhausted and the system throws in that case.
567  * @exception Cgu::Thread::TaskError This exception will be thrown if
568  * starting the specified minimum number of threads fails.
569  * @exception Cgu::Thread::MutexError This exception might be thrown
570  * if initialisation of the contained mutex fails. (It is often not
571  * worth checking for this, as it means either memory is exhausted or
572  * pthread has run out of other resources to create new mutexes.)
573  * @exception Cgu::Thread::CondError This exception might be thrown
574  * if initialisation of the contained condition variable fails. (It
575  * is often not worth checking for this, as it means either memory is
576  * exhausted or pthread has run out of other resources to create new
577  * condition variables.)
578  *
579  * Since 2.0.12
580  */
581  TaskManager(unsigned int max = 8, unsigned int min = 0,
582  unsigned int idle = 10000, bool blocking = true,
584 
585  /**
586  * The destructor will call stop_all(), unless that method has
587  * previously been called explicitly without throwing std::bad_alloc.
588  * If the blocking setting is true, the destructor will not return
589  * until the tasks remaining to be executed have finished (what is
590  * mean by "the tasks remaining to be executed" depends on the
591  * StopMode setting, for which see the documentation on the
592  * stop_all() method.) If the blocking setting is false, the
593  * destructor will return straight away: this is safe, because
594  * TaskManager's internals for running tasks have been implemented
595  * using reference counting and will not be deleted until all threads
596  * running on the TaskManager object have finished, although the
597  * remaining tasks should not attempt to call any of TaskManager's
598  * methods once the TaskManager object itself has been destroyed.
599  *
600  * The destructor is thread safe (any thread can destroy a
601  * TaskManager object) unless the blocking setting is true, in which
602  * case no task running on the TaskManager object may destroy the
603  * TaskManager object. Subject to that, it is not an error for a
604  * thread to destroy a TaskManager object and so invoke this
605  * destructor while another thread is already blocking in (if the
606  * blocking setting is true) or already out of (if the blocking
607  * setting is false) a call to stop_all() and remaining tasks are
608  * executing: if blocking, both calls (to stop_all() and to this
609  * destructor) would safely block together. Any given thread can
610  * similarly safely follow a non-blocking call to stop_all() by a
611  * non-blocking call to this destructor even though remaining tasks
612  * are executing. However, it is an error for a thread to call
613  * stop_all() after another thread has begun destruction of the
614  * TaskManager object (that is, after this destructor has been
615  * entered): there would then be an unresolvable race with the
616  * destructor.
617  *
618  * The destructor will not throw.
619  *
620  * If stop_all() has not previously been called explicitly and throws
621  * std::bad_alloc() when called in this destructor, the exception
622  * will be caught and consumed, but then the destructor will not
623  * block even if the blocking setting is true, and if the minimum
624  * number of threads is not 0 some threads might remain running
625  * during the entire program duration (albeit safely). Where the
626  * throwing of std::bad_alloc is a meaningful event (usually it
627  * isn't) and needs to be guarded against, call stop_all() explicitly
628  * before this destructor is entered, or use a minimum thread value
629  * of 0 and allow for the case of the destructor not blocking.
630  *
631  * Since 2.0.12
632  */
633  ~TaskManager();
634 
635 /* Only has effect if --with-glib-memory-slices-compat or
636  * --with-glib-memory-slices-no-compat option picked */
638 };
639 
640 } // namespace Thread
641 
642 } // namespace Cgu
643 
644 #endif