]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/thread/doc/async_executors.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / thread / doc / async_executors.qbk
CommitLineData
7c673cae
FG
1[/
2 / Copyright (c) 2014-2015 Vicente J. Botet Escriba
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 /]
7
8[//////////////////////////////////////////////////////////]
9[section:executors Executors and Schedulers -- EXPERIMENTAL]
10
11[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
12
13[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from this paper to show the differences.]
14
15Executors are objects that can execute units of work packaged as function objects. Boost.Thread differs from N3785 mainly in the an Executor doesn't needs to inherit from an abstract class Executor. Static polymorphism is used instead and type erasure is used internally.
16
17[////////////////////]
18[section Introduction]
19
20Multithreaded programs often involve discrete (sometimes small) units of work that are executed asynchronously. This often involves passing work units to some component that manages execution. We already have boost::async, which potentially executes a function asynchronously and eventually returns its result in a future. (“As if” by launching a new thread.)
21
22If there is a regular stream of small work items then we almost certainly don’t want to launch a new thread for each, and it’s likely that we want at least some control over which thread(s) execute which items. It is often convenient to represent that control as multiple executor objects. This allows programs to start executors when necessary, switch from one executor to another to control execution policy, and use multiple executors to prevent interference and thread exhaustion. Several possible implementations exist of the executor class and in practice there are a number of main groups of executors which have been found to be useful in real-world code (more implementations exist, this is simply a high level classification of them). These differ along a couple main dimensions, how many execution contexts will be used, how they are selected, and how they are prioritized.
23
24# Thread Pools
25 # Simple unbounded thread pool, which can queue up an unbounded amount of work and maintains a dedicated set of threads (up to some maximum) which
26dequeue and execute work as available.
27 # Bounded thread pools, which can be implemented as a specialization of the previous ones with a bounded queue or semaphore, which limits the amount of queuing in an attempt to bound the time spent waiting to execute and/or limit resource utilization for work tasks which hold state which is expensive to hold.
28 # Thread-spawning executors, in which each work always executes in a new thread.
29 # Prioritized thread pools, which have works which are not equally prioritized such that work can move to the front of the execution queue if necessary. This requires a special comparator or prioritization function to allow for work ordering and normally is implemented as a blocking priority queue in front of the pool instead of a blocking queue. This has many uses but is a somewhat specialized in nature and would unnecessarily clutter the initial interface.
30 # Work stealing thread pools, this is a specialized use case and is encapsulated in the ForkJoinPool in java, which allows lightweight work to be created by tasks in the pool and either run by the same thread for invocation efficiency or stolen by another thread without additional work. These have been left out until there is a more concrete fork-join proposal or until there is a more clear need as these can be complicated to implement
31
32# Mutual exclusion executors
33 # Serial executors, which guarantee all work to be executed such that no two works will execute concurrently. This allows for a sequence of operations to be queued in sequence and that sequential order is maintained and work can be queued on a separate thread but with no mutual exclusion required.
34 # Loop executor, in which one thread donates itself to the executor to execute all queued work. This is related to the serial executor in that it guarantees mutual exclusion, but instead guarantees a particular thread will execute the work. These are particularly useful for testing purposes where code assumes an executor but testing code desires control over execution.
35 # GUI thread executor, where a GUI framework can expose an executor interface to allow other threads to queue up work to be executed as part of the GUI thread. This behaves similarly to a loop executor, but must be implemented as a custom interface as part of the framework.
36
37# Inline executors, which execute inline to the thread which calls submit(). This has no queuing and behaves like a normal executor, but always uses the caller’s thread to execute. This allows parallel execution of works, though. This type of executor is often useful when there is an executor required by an interface, but when for performance reasons it’s better not to queue work or switch threads. This is often very useful as an optimization for work continuations which should execute immediately or quickly and can also be useful for optimizations when an interface requires an executor but the work tasks are too small to justify the overhead of a full thread pool.
38
39A question arises of which of these executors (or others) be included in this library. There are use cases for these and many other executors. Often it is useful to have more than one implemented executor (e.g. the thread pool) to have more precise control of where the work is executed due to the existence of a GUI thread, or for testing purposes. A few core executors are frequently useful and these have been outlined here as the core of what should be in this library, if common use cases arise for alternative executor implementations, they can be added in the future. The current set provided here are: a basic thread pool `basic_thread_pool`, a serial executor `serial_executor`, a loop executor `loop_executor`, an inline executor `inline_executor` and a thread-spawning executor `thread_executor`.
40[endsect]
41
42[/
43[/////////////////////////]
44[section:tutorial Tutorial]
45
46
47[endsect]
48]
49[////////////////]
50[section:examples Examples]
51
52[section:quick_sort Parallel Quick Sort]
53
54
55 #include <boost/thread/executors/basic_thread_pool.hpp>
56 #include <boost/thread/future.hpp>
57 #include <numeric>
58 #include <algorithm>
59 #include <functional>
60 #include <iostream>
61 #include <list>
62
63 template<typename T>
64 struct sorter
65 {
66 boost::basic_thread_pool pool;
67 typedef std::list<T> return_type;
68
69 std::list<T> do_sort(std::list<T> chunk_data)
70 {
71 if(chunk_data.empty()) {
72 return chunk_data;
73 }
74
75 std::list<T> result;
76 result.splice(result.begin(),chunk_data, chunk_data.begin());
77 T const& partition_val=*result.begin();
78
79 typename std::list<T>::iterator divide_point =
80 std::partition(chunk_data.begin(), chunk_data.end(),
81 [&](T const& val){return val<partition_val;});
82
83 std::list<T> new_lower_chunk;
84 new_lower_chunk.splice(new_lower_chunk.end(), chunk_data,
85 chunk_data.begin(), divide_point);
86 boost::future<std::list<T> > new_lower =
87 boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
88 std::list<T> new_higher(do_sort(chunk_data));
89 result.splice(result.end(),new_higher);
90 while(!new_lower.is_ready()) {
91 pool.schedule_one_or_yield();
92 }
93 result.splice(result.begin(),new_lower.get());
94 return result;
95 }
96 };
97
98 template<typename T>
99 std::list<T> parallel_quick_sort(std::list<T>& input) {
100 if(input.empty()) {
101 return input;
102 }
103 sorter<T> s;
104 return s.do_sort(input);
105 }
106
107
108[endsect]
109[endsect]
110
111
112[////////////////////////]
113[section:rationale Design Rationale]
114
115The authors of Boost.Thread have taken a different approach respect to N3785. Instead of basing all the design on an abstract executor class we make executor concepts. We believe that this is the good direction as a static polymorphic executor can be seen as a dynamic polymorphic executor using a simple adaptor. We believe also that it would make the library more usable, and more convenient for users.
116
117The major design decisions concern deciding what a unit of work is, how to manage with units of work and time related functions in a polymorphic way.
118
119An Executor is an object that schedules the closures that have been submitted to it, usually asynchronously. There could be multiple models of the Executor class. Some specific design notes:
120
121* Thread pools are well know models of the Executor concept, and this library does indeed include a basic_thread_pool class, but other implementations also exist, including the ability to schedule work on GUI threads, scheduling work on a donor thread, as well as several specializations of thread pools.
122
123* The choice of which executor to use is explicit. This is important for reasons described in the Motivation section. In particular, consider the common case of an asynchronous operation that itself spawns asynchronous operations. If both operations ran on the same executor, and if that executor had a bounded number of worker threads, then we could get deadlock. Programs often deal with such issues by splitting different kinds of work between different executors.
124
125* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable and robust way.
126
127* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is using without making it a template and is possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
128
129* Conceptually, an executor puts closures on a queue and at some point executes them. The queue is always unbounded, so adding a closure to an executor never blocks. (Defining “never blocks” formally is challenging, but informally we just mean that submit() is an ordinary function that executes something and returns, rather than waiting for the completion of some potentially long running operation in another thread.)
130
131[heading Closure]
132
133One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `void`.
134
135N3785 choose the more specific `std::function<void()>` as it provides only dynamic polymorphism and states that in practice the implementation of a template based approach or another approach is impractical. The authors of this library think that the template based approach is compatible with a dynamic based approach. They give some arguments:
136
137The first one is that a virtual function can not be a template. This is true but it is also true that the executor interface can provide the template functions that call to the virtual public functions. Another reason they give is that "a template parameter would complicate the interface without adding any real generality. In the end an executor class is going to need some kind of type erasure to handle all the different kinds of function objects with `void()` signature, and that’s exactly what std::function already does". We think that it is up to the executor to manage with this implementation details, not to the user.
138
139We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what she needs.
140
141The third one is related to performance. They assert that "any mechanism for storing closures on an executor’s queue will have to use some form of type erasure. There’s no reason to believe that a custom closure mechanism, written just for std::executor and used nowhere else within the standard library, would be better in that respect than `std::function<void()>`". We believe that the implementation can do better that storing the closure on a `std::function<void()>`. e.g. the implementation can use intrusive data to store the closure and the pointers to other nodes needed to store the closures in a given order.
142
143In addition `std::function<void()>` can not be constructed by moving the closure, so e.g. `std::packaged_task` could not be a Closure.
144
145[/
146[heading Scheduled work]
147
148The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding two member template functions to a class scheduled_executor that wraps an existing executor. This has several advantages:
149
150* The scheduled operations are available for all the executors.
151* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
152
153In order to manage with all the clocks, there are two alternatives:
154
155* transform the submit_at operation to a `submit_after` operation and let a single `scheduled_executor` manage with a single clock.
156* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
157
158The library chose the first of those options, largely for simplicity.
159]
160
161[heading Scheduled work]
162
163The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding a specific `scheduler` class that is not an executor and knows how to manage with the scheduling of timed tasks `submit_at`/`submit_after`.
164
165
166`scheduler` provides executor factories `at`/`after` given a specific `time_point` or a `duration`. The built executors wrap a reference to this scheduler and the time at which the submitted task will be executed.
167
168If we want to schedule these operations on an existing executor (as `serial_executor` does), these classes provide a `on` factory taking another executor as parameter and wraps both instance on the returned executor.
169
170 sch.on(tp).after(seconds(i)).submit(boost::bind(fn,i));
171
172This has several advantages:
173
174* The scheduled operations are available for all the executors via wrappers.
175* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
176
177In order to manage with all the clocks, this library propose generic solution. `scheduler<Clock>` know how to manage with the `submit_at`/`submit_after` `Clock::time_point`/`Clock::duration` tasks. Note that the durations on different clocks differ.
178
179[heading Not Handled Exceptions]
180As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
181Note that when we combine `boost::async` and `Executors`, the exception will be caught by the closure associated to the returned future, so that the exception is stored on the returned future, as for the other `async` overloads.
182
183[heading At thread entry]
184
185It is common idiom to set some thread local variable at the beginning of a thread. As Executors could instantiate threads internally these Executors shall have the ability to call a user specific function at thread entry on the executor constructor.
186
187For executors that don't instantiate any thread and that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
188
189[heading Cancelation]
190
191The library does not provision yet for the ability to cancel/interrupt work, though this is a commonly requested feature.
192
193This could be managed externally by an additional cancelation object that can be shared between the creator of the unit of work and the unit of work.
194
195We can think also of a cancelable closure that could be used in a more transparent way.
196
197An alternative is to make async return a cancelable_task but this will need also a cancelable closure.
198
199
200[/
201The library would provide in the future a cancelable_task that could support cancelation.
202
203 class cancelation_state
204 {
205 std::atomic<bool> requested;
206 std::atomic<bool> enabled;
207 std::condition_variable* cond;
208 std::mutex cond_mutex;
209 public:
210 cancelation_state() :
211 thread_cond(0)
212 {
213 }
214 void cancel()
215 {
216 requested.store(true, std::memory_order_relaxed);
217 std::lock_guard < std::mutex > lk(cond_mutex);
218 if (cond)
219 {
220 cond->notify_all();
221 }
222 }
223 bool cancellation_requested() const
224 {
225 return requested.load(std::memory_order_relaxed);
226 }
227 void enable()
228 {
229 enable.store(true, std::memory_order_relaxed);
230 }
231 void disable()
232 {
233 enable.store(false, std::memory_order_relaxed);
234 }
235 bool cancellation_enabled() const
236 {
237 return enabled.load(std::memory_order_relaxed);
238 }
239 void set_condition_variable(std::condition_variable& cv)
240 {
241 std::lock_guard < std::mutex > lk(cond_mutex);
242 cond = &cv;
243 }
244 void clear_condition_variable()
245 {
246 std::lock_guard < std::mutex > lk(cond_mutex);
247 cond = 0;
248 }
249 struct clear_cv_on_destruct
250 {
251 ~clear_cv_on_destruct()
252 {
253 this_thread_interrupt_flag.clear_condition_variable();
254 }
255 };
256 void cancelation_point();
257 void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk)
258 {
259 cancelation_point();
260 this_cancelable_state.set_condition_variable(cv);
261 this_cancelable_state::clear_cv_on_destruct guard;
262 interruption_point();
263 cv.wait_for(lk, std::chrono::milliseconds(1));
264 this_cancelable_state.clear_condition_variable();
265 cancelation_point();
266 }
267 class disable_cancelation
268 {
269 public:
270 disable_cancelation(const disable_cancelation&)= delete;
271 disable_cancelation& operator=(const disable_cancelation&)= delete;
272 disable_cancelation(cancelable_closure& closure)
273 noexcept ;
274 ~disable_cancelation() noexcept;
275 };
276 class restore_cancelation
277 {
278 public:
279 restore_cancelation(const restore_cancelation&) = delete;
280 restore_cancelation& operator=(const restore_cancelation&) = delete;
281 explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
282 ~restore_cancelation() noexcept;
283 };
284 };
285
286 template <class Closure>
287 struct cancelable_closure_mixin: cancelable_closure
288 {
289 void operator()
290 {
291 cancel_point();this->Closure::run();
292 }
293 };
294
295 struct my_clousure: cancelable_closure_mixin<my_clousure>
296 {
297 void run()
298 {
299 while ()
300 {
301 cancel_point();
302 }
303 }
304 }
305]
306
307[heading Current executor]
308
309The library does not provision for the ability to get the current executor, though having access to it could simplify a lot the user code.
310
311The reason is that the user can always use a thread_local variable and reset it using the `at_thread_entry ` member function.
312
313 thread_local current_executor_state_type current_executor_state;
314 executor* current_executor() { return current_executor_state.current_executor(); }
315 basic_thread_pool pool(
316 // at_thread_entry
317 [](basic_thread_pool& pool) {
318 current_executor_state.set_current_executor(pool);
319 }
320 );
321
322[
323[heading Default executor]
324
325The library authors share some of the concerns of the C++ standard committee (introduction of a new single shared resource, a singleton, could make it difficult to make it portable to all the environments) and that this library doesn't need to provide a default executor for the time been.
326
327The user can always define his default executor himself.
328
329 boost::generic_executor_ref default_executor()
330 {
331 static boost::basic_thread_pool tp(4);
332 return generic_executor_ref(tp);
333 }
334
335
336[endsect]
337
338
339[/////////////////////]
340[section:ref Reference]
341
342
343[////////////////////////////////]
344[section:concept_closure Concept `Closure`]
345
346
347A type `E` meets the `Closure` requirements if is a model of `Callable(void())` and a model of `CopyConstructible`/`MoveConstructible`.
348
349[endsect]
350[////////////////////////////////]
351[section:concept_executor Concept `Executor`]
352
353The `Executor` concept models the common operations of all the executors.
354
355A type `E` meets the `Executor` requirements if the following expressions are well-formed and have the specified semantics
356
357* `e.submit(lc);`
358* `e.submit(rc);`
359* `e.close();`
360* `b = e.closed();`
361* `e.try_executing_one();`
362* `e.reschedule_until(p);`
363
364where
365
366* `e` denotes a value of type `E`,
367* `lc` denotes a lvalue reference of type `Closure`,
368* `rc` denotes a rvalue reference of type `Closure`
369* `p` denotes a value of type `Predicate`
370
371[/////////////////////////////////////]
372[section:submitlc `e.submit(lc);`]
373
374[variablelist
375
376[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
377If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
378
379[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
380
381[[Return type:] [`void`.]]
382
383[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
384
385[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
386
387]
388
389[endsect]
390[/////////////////////////////////////]
391[section:submitrc `e.submit(rc);`]
392
393[variablelist
394
395[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
396If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
397
398[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
399
400[[Return type:] [`void`.]]
401
402[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
403
404[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
405
406]
407
408[endsect]
409[/////////////////////////////////////]
410[section:close `e.close();`]
411
412[variablelist
413
414[[Effects:] [close the executor `e` for submissions.]]
415
416[[Remark:] [The worker threads will work until there is no more closures to run.]]
417
418[[Return type:] [`void`.]]
419
420[[Throws:] [Whatever exception that can be thrown while ensuring the thread safety.]]
421
422[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
423
424]
425
426[endsect]
427[/////////////////////////////////////]
428[section:closed `b = e.closed();`]
429
430[variablelist
431
432[[Return type:] [`bool`.]]
433
434[[Return:] [whether the executor is closed for submissions.]]
435
436[[Throws:] [Whatever exception that can be throw while ensuring the thread safety.]]
437
438
439]
440
441[endsect]
442[/////////////////////////////////////]
443[section:try_executing_one `e.try_executing_one();`]
444
445[variablelist
446
447[[Effects:] [try to execute one work.]]
448
449[[Remark:] [whether a work has been executed.]]
450
451[[Return type:] [`bool`.]]
452
453[[Return:] [Whether a work has been executed.]]
454
455[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
456
457]
458
459[endsect]
460[/////////////////////////////////////]
461[section:reschedule_until `e.reschedule_until(p);`]
462
463[variablelist
464
465[[Requires:] [This must be called from a scheduled work]]
466
467[[Effects:] [reschedule works until `p()`.]]
468
469[[Return type:] [`bool`.]]
470
471[[Return:] [Whether a work has been executed.]]
472
473[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
474
475]
476
477[endsect]
478
479[endsect]
480
481[/////////////////////////]
482[section:work Class `work`]
483
484 #include <boost/thread/work.hpp>
485 namespace boost {
486 typedef 'implementation_defined' work;
487 }
488
489[variablelist
490
491[[Requires:] [work is a model of 'Closure']]
492
493]
494
495[endsect]
496
497[/////////////////////////////////]
498[section:executor Class `executor`]
499
500Executor abstract base class.
501
502 #include <boost/thread/executor.hpp>
503 namespace boost {
504 class executor
505 {
506 public:
507 typedef boost::work work;
508
509 executor(executor const&) = delete;
510 executor& operator=(executor const&) = delete;
511
512 executor();
513 virtual ~executor() {};
514
515 virtual void close() = 0;
516 virtual bool closed() = 0;
517
518 virtual void submit(work&& closure) = 0;
519 virtual void submit(work& closure) = 0;
520 template <typename Closure>
521 void submit(Closure&& closure);
522
523 virtual bool try_executing_one() = 0;
524 template <typename Pred>
525 bool reschedule_until(Pred const& pred);
526 };
527 }
528
529[/////////////////////////////////////]
530[section:constructor Constructor `executor()`]
531
532 executor();
533
534[variablelist
535
536[[Effects:] [Constructs an executor. ]]
537
538[[Throws:] [Nothing. ]]
539
540]
541
542
543[endsect]
544[/////////////////////////////////////]
545[section:constructor Destructor `~executor()`]
546
547 virtual ~executor();
548
549[variablelist
550
551[[Effects:] [Destroys the executor.]]
552
553[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
554
555]
556
557
558[endsect]
559
560[endsect]
561
562[//////////////////////////////////////////////////////////]
563[section:executor_adaptor Template Class `executor_adaptor`]
564
565Polymorphic adaptor of a model of Executor to an executor.
566
567 #include <boost/thread/executor.hpp>
568 namespace boost {
569 template <typename Executor>
570 class executor_adaptor : public executor
571 {
572 Executor ex; // for exposition only
573 public:
574 typedef executor::work work;
575
576 executor_adaptor(executor_adaptor const&) = delete;
577 executor_adaptor& operator=(executor_adaptor const&) = delete;
578
579 template <typename ...Args>
580 executor_adaptor(Args&& ... args);
581
582 Executor& underlying_executor() noexcept;
583
584 void close();
585 bool closed();
586
587 void submit(work&& closure);
588 void submit(work& closure);
589
590 bool try_executing_one();
591
592 };
593 }
594
595[/////////////////////////////////////]
596[section:constructor Constructor `executor_adaptor(Args&& ...)`]
597
598 template <typename ...Args>
599 executor_adaptor(Args&& ... args);
600
601[variablelist
602
603[[Effects:] [Constructs an executor_adaptor. ]]
604
605[[Throws:] [Nothing. ]]
606
607]
608
609
610[endsect]
611[/////////////////////////////////////]
612[section:destructor Destructor `~executor_adaptor()`]
613
614 virtual ~executor_adaptor();
615
616[variablelist
617
618[[Effects:] [Destroys the executor_adaptor.]]
619
620[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
621
622]
623
624[endsect]
625[/////////////////////////////////////]
626[section:underlying_executor Function member `underlying_executor()`]
627
628 Executor& underlying_executor() noexcept;
629
630[variablelist
631
632[[Return:] [The underlying executor instance. ]]
633
634]
635
636
637[endsect]
638
639[endsect]
640
641[/////////////////////////////////]
642[section:generic_executor_ref Class `generic_executor_ref`]
643
644Executor abstract base class.
645
646 #include <boost/thread/generic_executor_ref.hpp>
647 namespace boost {
648 class generic_executor_ref
649 {
650 public:
651 generic_executor_ref(generic_executor_ref const&);
652 generic_executor_ref& operator=(generic_executor_ref const&);
653
654 template <class Executor>
655 generic_executor_ref(Executor& ex);
656 generic_executor_ref() {};
657
658 void close() = 0;
659 bool closed() = 0;
660
661 template <typename Closure>
662 void submit(Closure&& closure);
663
664 virtual bool try_executing_one() = 0;
665 template <typename Pred>
666 bool reschedule_until(Pred const& pred);
667 };
668 }
669
670[endsect]
671
672[//////////////////////////////////////////////////////////]
673[section: scheduler Template Class `scheduler `]
674
675Scheduler providing time related functions. Note that `scheduler` is not an Executor.
676
677 #include <boost/thread/executors/scheduler.hpp>
678 namespace boost {
679
680 template <class Clock=steady_clock>
681 class scheduler
682 {
683 public:
684 using work = boost::function<void()> ;
685 using clock = Clock;
686
687 scheduler(scheduler const&) = delete;
688 scheduler& operator=(scheduler const&) = delete;
689
690 scheduler();
691 ~scheduler();
692
693 void close();
694 bool closed();
695
696 template <class Duration, typename Closure>
697 void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
698 template <class Rep, class Period, typename Closure>
699 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
700
701 template <class Duration>
702 at_executor<scheduler> submit_at(chrono::time_point<clock,Duration> abs_time);
703 template <class Rep, class Period>
704 at_executor<scheduler> submit_after(chrono::duration<Rep,Period> rel_time);
705
706 template <class Executor>
707 scheduler_executor_wrapper<scheduler, Executor> on(Executor& ex);
708
709 };
710 }
711
712[/////////////////////////////////////]
713[section:constructor Constructor `scheduler()`]
714
715 scheduler();
716
717[variablelist
718
719[[Effects:] [Constructs a `scheduler`. ]]
720
721[[Throws:] [Nothing. ]]
722
723]
724
725
726[endsect]
727[/////////////////////////////////////]
728[section:destructor Destructor `~scheduler()`]
729
730 ~scheduler();
731
732[variablelist
733
734[[Effects:] [Destroys the scheduler.]]
735
736[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
737
738]
739
740[endsect]
741[/////////////////////////////////////]
742[section:submit_at Template Function Member `submit_at()`]
743
744 template <class Clock, class Duration, typename Closure>
745 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
746
747[variablelist
748
749[[Effects:] [Schedule a `closure` to be executed at `abs_time`. ]]
750
751[[Throws:] [Nothing.]]
752
753]
754
755
756[endsect]
757[/////////////////////////////////////]
758[section:submit_after Template Function Member `submit_after()`]
759
760 template <class Rep, class Period, typename Closure>
761 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
762
763[variablelist
764
765[[Effects:] [Schedule a `closure` to be executed after `rel_time`. ]]
766
767[[Throws:] [Nothing.]]
768
769]
770
771
772[endsect]
773
774[endsect]
775
776[//////////////////////////////////////////////////////////]
777[section:at_executor Template Class `at_executor`]
778
779
780 #include <boost/thread/executors/scheduler.hpp>
781 namespace boost {
782
783 template <class Scheduler>
784 class at_executor
785 {
786 public:
787 using work = Scheduler::work;
788 using clock = Scheduler::clock;
789
790 at_executor(at_executor const&) = default;
791 at_executor(at_executor &&) = default;
792 at_executor& operator=(at_executor const&) = default;
793 at_executor& operator=(at_executor &&) = default;
794
795 at_executor(Scheduler& sch, clock::time_point const& tp);
796 ~at_executor();
797
798 void close();
799 bool closed();
800
801 Scheduler& underlying_scheduler();
802
803 template <class Closure>
804 void submit(Closure&& closure);
805 template <class Duration, typename Work>
806 void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
807 template <class Rep, class Period, typename Work>
808 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
809
810 template <class Executor>
811 resubmit_at_executor<Scheduler, Executor> on(Executor& ex);
812
813 };
814 }
815
816[/////////////////////////////////////]
817[section:constructor Constructor `at_executor(Scheduler&, clock::time_point const&)`]
818
819 at_executor(Scheduler& sch, clock::time_point const& tp);
820
821[variablelist
822
823[[Effects:] [Constructs a `at_executor`. ]]
824
825[[Throws:] [Nothing. ]]
826
827]
828
829
830[endsect]
831[/////////////////////////////////////]
832[section:destructor Destructor `~at_executor()`]
833
834 ~at_executor();
835
836[variablelist
837
838[[Effects:] [Destroys the `at_executor`.]]
839
840[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
841
842]
843
844[endsect]
845[/////////////////////////////////////]
846[section:underlying_scheduler Function member `underlying_scheduler()`]
847
848 Scheduler& underlying_scheduler() noexcept;
849
850[variablelist
851
852[[Return:] [The underlying scheduler instance. ]]
853
854]
855
856[endsect]
857[/////////////////////////////////////]
858[section:submit_at Template Function Member `submit()`]
859
860 template <typename Closure>
861 void submit(Closure&& closure);
862
863[variablelist
864
865[[Effects:] [Schedule the `closure` to be executed at the `abs_time` given at construction time. ]]
866
867[[Throws:] [Nothing.]]
868
869]
870
871[endsect]
872[/////////////////////////////////////]
873[section:submit_at Template Function Member `submit_at()`]
874
875 template <class Clock, class Duration, typename Closure>
876 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
877
878[variablelist
879
880[[Effects:] [Schedule a `closure` to be executed at `abs_time`. ]]
881
882[[Throws:] [Nothing.]]
883
884]
885
886
887[endsect]
888[/////////////////////////////////////]
889[section:submit_after Template Function Member `submit_after()`]
890
891 template <class Rep, class Period, typename Closure>
892 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
893
894[variablelist
895
896[[Effects:] [Schedule a `closure` to be executed after `rel_time`. ]]
897
898[[Throws:] [Nothing.]]
899
900]
901
902
903[endsect]
904
905[endsect]
906
907
908[//////////////////////////////////////////////////////////]
909[section:scheduler_executor_wrapper Template Class `scheduler_executor_wrapper`]
910
911 #include <boost/thread/executors/scheduler.hpp>
912 namespace boost {
913
914 template <class Scheduler, class Executor>
915 class scheduler_executor_wrapper
916 {
917 public:
918 using work = Scheduler::work;
919 using clock = Scheduler::clock;
920
921 scheduler_executor_wrapper(scheduler_executor_wrapper const&) = default;
922 scheduler_executor_wrapper(scheduler_executor_wrapper &&) = default;
923 scheduler_executor_wrapper& operator=(scheduler_executor_wrapper const&) = default;
924 scheduler_executor_wrapper& operator=(scheduler_executor_wrapper &&) = default;
925
926 scheduler_executor_wrapper(Scheduler& sch, Executor& ex);
927
928 ~scheduler_executor_wrapper();
929
930 void close();
931 bool closed();
932
933 Executor& underlying_executor();
934 Scheduler& underlying_scheduler();
935
936 template <class Closure>
937 void submit(Closure&& closure);
938 template <class Duration, typename Work>
939 void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
940 template <class Rep, class Period, typename Work>
941 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
942
943 template <class Duration>
944 resubmit_at_executor<Scheduler, Executor> at(chrono::time_point<clock,Duration> abs_time);
945 template <class Rep, class Period>
946 resubmit_at_executor<Scheduler, Executor> after(chrono::duration<Rep,Period> rel_time);
947
948 };
949 }
950
951[/////////////////////////////////////]
952[section:constructor Constructor `scheduler_executor_wrapper(Scheduler&, Executor&)`]
953
954 scheduler_executor_wrapper(Scheduler& sch, Executor& ex);
955
956[variablelist
957
958[[Effects:] [Constructs a `scheduler_executor_wrapper`. ]]
959
960[[Throws:] [Nothing. ]]
961
962]
963
964[endsect]
965[/////////////////////////////////////]
966[section:destructor Destructor `~scheduler_executor_wrapper()`]
967
968 ~scheduler_executor_wrapper();
969
970[variablelist
971
972[[Effects:] [Destroys the `scheduler_executor_wrapper`.]]
973
974[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
975
976]
977
978[endsect]
979[/////////////////////////////////////]
980[section:underlying_scheduler Function member `underlying_scheduler()`]
981
982 Scheduler& underlying_scheduler() noexcept;
983
984[variablelist
985
986[[Return:] [The underlying scheduler instance. ]]
987
988]
989
990[endsect]
991[/////////////////////////////////////]
992[section:underlying_executor Function member `underlying_executor()`]
993
994 Executor& underlying_executor() noexcept;
995
996[variablelist
997
998[[Return:] [The underlying executor instance. ]]
999
1000]
1001
1002[endsect]
1003[/////////////////////////////////////]
1004[section:submit_at Template Function Member `submit()`]
1005
1006 template <typename Closure>
1007 void submit(Closure&& closure);
1008
1009[variablelist
1010
1011[[Effects:] [Submit the `closure` on the underlying executor. ]]
1012
1013[[Throws:] [Nothing.]]
1014
1015]
1016
1017[endsect]
1018[/////////////////////////////////////]
1019[section:submit_at Template Function Member `submit_at()`]
1020
1021 template <class Clock, class Duration, typename Closure>
1022 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
1023
1024[variablelist
1025
1026[[Effects:] [Resubmit the `closure` to be executed on the underlying executor at `abs_time`. ]]
1027
1028[[Throws:] [Nothing.]]
1029
1030]
1031
1032[endsect]
1033[/////////////////////////////////////]
1034[section:submit_after Template Function Member `submit_after()`]
1035
1036 template <class Rep, class Period, typename Closure>
1037 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
1038
1039[variablelist
1040
1041[[Effects:] [Resubmit the `closure` to be executed on the underlying executor after `rel_time`. ]]
1042
1043[[Throws:] [Nothing.]]
1044
1045]
1046
1047[endsect]
1048
1049[endsect]
1050
1051
1052[//////////////////////////////////////////////////////////]
1053[section:resubmit_at_executor Template Class `resubmit_at_executor`]
1054
1055`Executor` wrapping an `Scheduler`, an `Executor` and a `time_point` providing an `Executor` interface.
1056
1057 #include <boost/thread/executors/scheduler.hpp>
1058 namespace boost {
1059
1060 template <class Scheduler, class Executor>
1061 class resubmit_at_executor
1062 {
1063 public:
1064 using work = Scheduler::work;
1065 using clock = Scheduler::clock;
1066
1067 resubmit_at_executor(resubmit_at_executor const&) = default;
1068 resubmit_at_executor(resubmit_at_executor &&) = default;
1069 resubmit_at_executor& operator=(resubmit_at_executor const&) = default;
1070 resubmit_at_executor& operator=(resubmit_at_executor &&) = default;
1071
1072 template <class Duration>
1073 resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point<Duration> const& tp);
1074 ~resubmit_at_executor();
1075
1076 void close();
1077 bool closed();
1078
1079 Executor& underlying_executor();
1080 Scheduler& underlying_scheduler();
1081
1082 template <class Closure>
1083 void submit(Closure&& closure);
1084 template <class Duration, typename Work>
1085 void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
1086 template <class Rep, class Period, typename Work>
1087 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
1088
1089 };
1090 }
1091
1092
1093[/////////////////////////////////////]
1094[section:constructor Constructor `resubmit_at_executor(Scheduler&, Executor&, clock::time_point<Duration>)`]
1095
1096 template <class Duration>
1097 resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point<Duration> const& tp);
1098
1099[variablelist
1100
1101[[Effects:] [Constructs a `resubmit_at_executor`. ]]
1102
1103[[Throws:] [Nothing. ]]
1104
1105]
1106
1107
1108[endsect]
1109[/////////////////////////////////////]
1110[section:destructor Destructor `~resubmit_at_executor()`]
1111
1112 ~resubmit_at_executor();
1113
1114[variablelist
1115
1116[[Effects:] [Destroys the executor_adaptor.]]
1117
1118[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1119
1120]
1121
1122[endsect]
1123[/////////////////////////////////////]
1124[section:underlying_executor Function member `underlying_executor()`]
1125
1126 Executor& underlying_executor() noexcept;
1127
1128[variablelist
1129
1130[[Return:] [The underlying executor instance. ]]
1131
1132]
1133
1134[endsect]
1135[/////////////////////////////////////]
1136[section:underlying_scheduler Function member `underlying_scheduler()`]
1137
1138 Scheduler& underlying_scheduler() noexcept;
1139
1140[variablelist
1141
1142[[Return:] [The underlying scheduler instance. ]]
1143
1144]
1145
1146[endsect]
1147[/////////////////////////////////////]
1148[section:submit_at Template Function Member `submit()`]
1149
1150 template <typename Closure>
1151 void submit(Closure&& closure);
1152
1153[variablelist
1154
1155[[Effects:] [Resubmit the `closure` to be executed on the underlying executor at the `abs_time` given at construction time. ]]
1156
1157[[Throws:] [Nothing.]]
1158
1159]
1160
1161[endsect]
1162[/////////////////////////////////////]
1163[section:submit_at Template Function Member `submit_at()`]
1164
1165 template <class Clock, class Duration, typename Closure>
1166 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
1167
1168[variablelist
1169
1170[[Effects:] [Resubmit the `closure` to be executed on the underlying executor at `abs_time`. ]]
1171
1172[[Throws:] [Nothing.]]
1173
1174]
1175
1176[endsect]
1177[/////////////////////////////////////]
1178[section:submit_after Template Function Member `submit_after()`]
1179
1180 template <class Rep, class Period, typename Closure>
1181 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
1182
1183[variablelist
1184
1185[[Effects:] [Resubmit the `closure` to be executed on the underlying executor after `rel_time`. ]]
1186
1187[[Throws:] [Nothing.]]
1188
1189]
1190
1191[endsect]
1192
1193[endsect]
1194
1195
1196[//////////////////////////////////////////////////////////]
1197[/
1198[section:scheduled_executor_ref Template Class `scheduled_executor_ref`]
1199
1200Executor providing time related functions.
1201
1202 #include <boost/thread/executors/scheduled_executor_ref.hpp>
1203 namespace boost {
1204 template <class Executor>
1205 class scheduled_executor_ref
1206 {
1207 Executor& ex;
1208 public:
1209 typedef executor::work work;
1210
1211 scheduled_executor_ref(scheduled_executor_ref const&) = delete;
1212 scheduled_executor_ref& operator=(scheduled_executor_ref const&) = delete;
1213
1214 template <class Rep, class Period>
1215 scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
1216
1217 Executor& underlying_executor() noexcept;
1218
1219 void close();
1220 bool closed();
1221
1222 void submit(work&& closure);
1223 void submit(work& closure);
1224 template <typename Closure>
1225 void submit(Closure&& closure);
1226
1227 bool try_executing_one();
1228 template <typename Pred>
1229 bool reschedule_until(Pred const& pred);
1230
1231 template <class Clock, class Duration, typename Closure>
1232 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
1233 template <class Rep, class Period, typename Closure>
1234 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
1235 };
1236 }
1237
1238[/////////////////////////////////////]
1239[section:constructor Constructor `scheduled_executor_ref(Executor&, chrono::duration<Rep, Period>)`]
1240
1241 template <class Rep, class Period>
1242 scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
1243
1244[variablelist
1245
1246[[Effects:] [Constructs a scheduled_executor_ref. ]]
1247
1248[[Throws:] [Nothing. ]]
1249
1250]
1251
1252
1253[endsect]
1254[/////////////////////////////////////]
1255[section:destructor Destructor `~scheduled_executor_ref()`]
1256
1257 ~scheduled_executor_ref();
1258
1259[variablelist
1260
1261[[Effects:] [Destroys the executor_adaptor.]]
1262
1263[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1264
1265]
1266
1267[endsect]
1268[/////////////////////////////////////]
1269[section:underlying_executor Function member `underlying_executor()`]
1270
1271 Executor& underlying_executor() noexcept;
1272
1273[variablelist
1274
1275[[Return:] [The underlying executor instance. ]]
1276
1277]
1278
1279[endsect]
1280[/////////////////////////////////////]
1281[section:submit_at Template Function Member `submit()`]
1282
1283 template <typename Closure>
1284 void submit(Closure&& closure);
1285
1286[variablelist
1287
1288[[Effects:] [Resubmit the `closure` to be executed on the underlying executor. ]]
1289
1290[[Throws:] [Nothing.]]
1291
1292]
1293
1294[endsect]
1295[/////////////////////////////////////]
1296[section:submit_at Template Function Member `submit_at()`]
1297
1298 template <class Clock, class Duration, typename Closure>
1299 void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
1300
1301[variablelist
1302
1303[[Effects:] [Schedule a `closure` to be executed at `abs_time`. ]]
1304
1305[[Throws:] [Nothing.]]
1306
1307]
1308
1309
1310[endsect]
1311[/////////////////////////////////////]
1312[section:submit_after Template Function Member `submit_after()`]
1313
1314 template <class Rep, class Period, typename Closure>
1315 void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
1316
1317[variablelist
1318
1319[[Effects:] [Schedule a `closure` to be executed after `rel_time`. ]]
1320
1321[[Throws:] [Nothing.]]
1322
1323]
1324
1325[endsect]
1326
1327
1328[endsect]
1329]
1330
1331[//////////////////////////////////////////////////////////]
1332[section:serial_executor Template Class `serial_executor`]
1333
1334A serial executor ensuring that there are no two work units that executes concurrently.
1335
1336 #include <boost/thread/serial_executor.hpp>
1337 namespace boost {
1338 template <class Executor>
1339 class serial_executor
1340 {
1341 public:
1342 serial_executor(serial_executor const&) = delete;
1343 serial_executor& operator=(serial_executor const&) = delete;
1344
1345 template <class Executor>
1346 serial_executor(Executor& ex);
1347
1348 Executor& underlying_executor() noexcept;
1349
1350 void close();
1351 bool closed();
1352
1353 template <typename Closure>
1354 void submit(Closure&& closure);
1355
1356 bool try_executing_one();
1357 template <typename Pred>
1358 bool reschedule_until(Pred const& pred);
1359
1360 };
1361 }
1362
1363[/////////////////////////////////////]
1364[section:constructor Constructor `serial_executor(Executor&)`]
1365
1366 template <class Executor>
1367 serial_executor(Executor& ex);
1368
1369[variablelist
1370
1371[[Effects:] [Constructs a serial_executor. ]]
1372
1373[[Throws:] [Nothing. ]]
1374
1375]
1376
1377
1378[endsect]
1379[/////////////////////////////////////]
1380[section:destructor Destructor `~serial_executor()`]
1381
1382 ~serial_executor();
1383
1384[variablelist
1385
1386[[Effects:] [Destroys the serial_executor.]]
1387
1388[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1389
1390]
1391
1392[endsect]
1393[/////////////////////////////////////]
1394[section:underlying_executor Function member `underlying_executor()`]
1395
1396 generic_executor_ref& underlying_executor() noexcept;
1397
1398[variablelist
1399
1400[[Return:] [The underlying executor instance. ]]
1401
1402[[Throws:] [Nothing.]]
1403
1404]
1405
1406
1407[endsect]
1408
1409[endsect]
1410
1411[//////////////////////////////////////////////////////////]
1412[section:generic_serial_executor Class `generic_serial_executor`]
1413
1414A serial executor ensuring that there are no two work units that executes concurrently.
1415
1416 #include <boost/thread/generic_serial_executor.hpp>
1417 namespace boost {
1418 class generic_serial_executor
1419 {
1420 public:
1421 generic_serial_executor(generic_serial_executor const&) = delete;
1422 generic_serial_executor& operator=(generic_serial_executor const&) = delete;
1423
1424 template <class Executor>
1425 generic_serial_executor(Executor& ex);
1426
1427 generic_executor_ref& underlying_executor() noexcept;
1428
1429 void close();
1430 bool closed();
1431
1432 template <typename Closure>
1433 void submit(Closure&& closure);
1434
1435 bool try_executing_one();
1436 template <typename Pred>
1437 bool reschedule_until(Pred const& pred);
1438
1439 };
1440 }
1441
1442[/////////////////////////////////////]
1443[section:constructor Constructor `generic_serial_executor(Executor&)`]
1444
1445 template <class Executor>
1446 generic_serial_executor(Executor& ex);
1447
1448[variablelist
1449
1450[[Effects:] [Constructs a serial_executor. ]]
1451
1452[[Throws:] [Nothing. ]]
1453
1454]
1455
1456
1457[endsect]
1458[/////////////////////////////////////]
1459[section:destructor Destructor `~serial_executor()`]
1460
1461 ~generic_serial_executor();
1462
1463[variablelist
1464
1465[[Effects:] [Destroys the serial_executor.]]
1466
1467[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1468
1469]
1470
1471[endsect]
1472[/////////////////////////////////////]
1473[section:underlying_executor Function member `underlying_executor()`]
1474
1475 Executor& underlying_executor() noexcept;
1476
1477[variablelist
1478
1479[[Return:] [The underlying executor instance. ]]
1480
1481]
1482
1483
1484[endsect]
1485
1486[endsect]
1487
1488
1489[//////////////////////////////////////////////////////////]
1490[section:inline_executor Class `inline_executor`]
1491
1492A serial executor ensuring that there are no two work units that executes concurrently.
1493
1494 #include <boost/thread/inline_executor.hpp>
1495 namespace boost {
1496 class inline_executor
1497 {
1498 public:
1499 inline_executor(inline_executor const&) = delete;
1500 inline_executor& operator=(inline_executor const&) = delete;
1501
1502 inline_executor();
1503
1504 void close();
1505 bool closed();
1506
1507 template <typename Closure>
1508 void submit(Closure&& closure);
1509
1510 bool try_executing_one();
1511 template <typename Pred>
1512 bool reschedule_until(Pred const& pred);
1513
1514 };
1515 }
1516
1517[/////////////////////////////////////]
1518[section:constructor Constructor `inline_executor()`]
1519
1520 inline_executor();
1521
1522[variablelist
1523
1524[[Effects:] [Constructs an inline_executor. ]]
1525
1526[[Throws:] [Nothing. ]]
1527
1528]
1529
1530
1531[endsect]
1532[/////////////////////////////////////]
1533[section:destructor Destructor `~inline_executor()`]
1534
1535 ~inline_executor();
1536
1537[variablelist
1538
1539[[Effects:] [Destroys the inline_executor.]]
1540
1541[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1542
1543]
1544
1545[endsect]
1546
1547
1548[endsect]
1549
1550
1551
1552
1553[///////////////////////////////////////]
1554[section:basic_thread_pool Class `basic_thread_pool`]
1555
1556A thread pool with up to a fixed number of threads.
1557
1558 #include <boost/thread/executors/basic_thread_pool.hpp>
1559 namespace boost {
1560 class basic_thread_pool
1561 {
1562 public:
1563
1564 basic_thread_pool(basic_thread_pool const&) = delete;
1565 basic_thread_pool& operator=(basic_thread_pool const&) = delete;
1566
1567 basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
1568 template <class AtThreadEntry>
1569 basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
1570 ~basic_thread_pool();
1571
1572 void close();
1573 bool closed();
1574
1575 template <typename Closure>
1576 void submit(Closure&& closure);
1577
1578 bool try_executing_one();
1579
1580 template <typename Pred>
1581 bool reschedule_until(Pred const& pred);
1582
1583 };
1584 }
1585
1586[/////////////////////////////////////]
1587[section:constructor Constructor `basic_thread_pool(unsigned const)`]
1588
1589[variablelist
1590
1591[[Effects:] [creates a thread pool that runs closures on `thread_count` threads. ]]
1592
1593[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
1594
1595]
1596
1597
1598[endsect]
1599[/////////////////////////////////////]
1600[section:destructor Destructor `~basic_thread_pool()`]
1601
1602 ~basic_thread_pool();
1603
1604[variablelist
1605
1606[[Effects:] [Destroys the thread pool.]]
1607
1608[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1609
1610]
1611[endsect]
1612
1613[endsect]
1614
1615[///////////////////////////////////////]
1616[section:thread_executor Class `thread_executor`]
1617
1618A thread_executor with a threads for each task.
1619
1620 #include <boost/thread/executors/thread_executor.hpp>
1621 namespace boost {
1622 class thread_executor
1623 {
1624 public:
1625
1626 thread_executor(thread_executor const&) = delete;
1627 thread_executor& operator=(thread_executor const&) = delete;
1628
1629 thread_executor();
1630 template <class AtThreadEntry>
1631 basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
1632 ~thread_executor();
1633
1634 void close();
1635 bool closed();
1636
1637 template <typename Closure>
1638 void submit(Closure&& closure);
1639
1640 };
1641 }
1642
1643[/////////////////////////////////////]
1644[section:constructor Constructor `thread_executor()`]
1645
1646[variablelist
1647
1648[[Effects:] [creates a thread_executor. ]]
1649
1650[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
1651
1652]
1653
1654
1655[endsect]
1656[/////////////////////////////////////]
1657[section:destructor Destructor `~thread_executor()`]
1658
1659 ~thread_executor();
1660
1661[variablelist
1662
1663[[Effects:] [Waits for closures (if any) to complete, then joins and destroys the threads.]]
1664
1665[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1666
1667]
1668[endsect]
1669
1670[endsect]
1671
1672
1673[/////////////////////////////////]
1674[section:loop_executor Class `loop_executor`]
1675
1676A user scheduled executor.
1677
1678 #include <boost/thread/loop_executor.hpp>
1679 namespace boost {
1680 class loop_executor
1681 {
1682 public:
1683
1684 loop_executor(loop_executor const&) = delete;
1685 loop_executor& operator=(loop_executor const&) = delete;
1686
1687 loop_executor();
1688 ~loop_executor();
1689
1690 void close();
1691 bool closed();
1692
1693 template <typename Closure>
1694 void submit(Closure&& closure);
1695
1696 bool try_executing_one();
1697 template <typename Pred>
1698 bool reschedule_until(Pred const& pred);
1699
1700 void loop();
1701 void run_queued_closures();
1702 };
1703 }
1704
1705[/////////////////////////////////////]
1706[section:constructor Constructor `loop_executor()`]
1707
1708 loop_executor();
1709
1710[variablelist
1711
1712[[Effects:] [creates an executor that runs closures using one of its closure-executing methods. ]]
1713
1714[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
1715
1716]
1717
1718
1719[endsect]
1720[/////////////////////////////////////]
1721[section:destructor Destructor `~loop_executor()`]
1722
1723 virtual ~loop_executor();
1724
1725[variablelist
1726
1727[[Effects:] [Destroys the executor.]]
1728
1729[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
1730
1731]
1732[endsect]
1733[/////////////////////////////////////]
1734[section:loop Function member `loop()`]
1735
1736 void loop();
1737
1738[variablelist
1739
1740[[Return:] [reschedule works until `closed()` or empty. ]]
1741
1742[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
1743
1744]
1745
1746
1747[endsect]
1748
1749[/////////////////////////////////////]
1750[section:run_queued_closures Function member `run_queued_closures()`]
1751
1752 void run_queued_closures();
1753
1754[variablelist
1755
1756[[Return:] [reschedule the enqueued works. ]]
1757
1758[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
1759
1760]
1761
1762
1763[endsect]
1764
1765
1766
1767[endsect]
1768
1769[endsect]
1770
1771[endsect]