mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-11 23:52:29 +00:00
Merge pull request #57 from nat-goodspeed/develop
Miscellaneous promised documentation tweaks
This commit is contained in:
@@ -15,6 +15,27 @@ barrier they must wait until all `n` fibers have arrived. Once the `n`-th
|
||||
fiber has reached the barrier, all the waiting fibers can proceed, and the
|
||||
barrier is reset.
|
||||
|
||||
The fact that the barrier automatically resets is significant. Consider a case
|
||||
in which you launch some number of fibers and want to wait only until the
|
||||
first of them has completed. You might be tempted to use a `barrier(2)` as the
|
||||
synchronization mechanism, making each new fiber call its [member_link
|
||||
barrier..wait] method, then calling `wait()` in the launching fiber to wait
|
||||
until the first other fiber completes.
|
||||
|
||||
That will in fact unblock the launching fiber. The unfortunate part is that it
|
||||
will continue blocking the ['remaining] fibers.
|
||||
|
||||
Consider the following scenario:
|
||||
|
||||
# Fiber "main" launches fibers A, B, C and D, then calls `barrier::wait()`.
|
||||
# Fiber C finishes first and likewise calls `barrier::wait()`.
|
||||
# Fiber "main" is unblocked, as desired.
|
||||
# Fiber B calls `barrier::wait()`. Fiber B is ['blocked]!
|
||||
# Fiber A calls `barrier::wait()`. Fibers A and B are unblocked.
|
||||
# Fiber D calls `barrier::wait()`. Fiber D is blocked indefinitely.
|
||||
|
||||
(See also [link wait_first_simple_section when_any, simple completion].)
|
||||
|
||||
[note It is unwise to tie the lifespan of a barrier to any one of its
|
||||
participating fibers. Although conceptually all waiting fibers awaken
|
||||
"simultaneously," because of the nature of fibers, in practice they will
|
||||
|
||||
@@ -85,19 +85,12 @@ allocating `priority_props` instances on the heap.
|
||||
|
||||
[heading Replace Default Scheduler]
|
||||
|
||||
You must call [function_link set_scheduling_algorithm] at the start of each
|
||||
You must call [function_link use_scheduling_algorithm] at the start of each
|
||||
thread on which you want __boost_fiber__ to use your custom scheduler rather
|
||||
than its own default [class_link round_robin]. Specifically, you must call
|
||||
`set_scheduling_algorithm()` before performing any other __boost_fiber__
|
||||
`use_scheduling_algorithm()` before performing any other __boost_fiber__
|
||||
operations on that thread.
|
||||
|
||||
It works to instantiate your custom [template_link
|
||||
sched_algorithm_with_properties] subclass on the stack at the start of your
|
||||
thread function, passing the instance pointer to `set_scheduling_algorithm()`.
|
||||
This ensures that your scheduler instance will live as long as the thread
|
||||
itself. (Of course `main()` is, in effect, the thread function for the
|
||||
application's main thread.)
|
||||
|
||||
[main]
|
||||
|
||||
[heading Use Properties]
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
template< typename PROPS >
|
||||
struct sched_algorithm_with_properties;
|
||||
class round_robin;
|
||||
void set_scheduling_algorithm( sched_algorithm * al)
|
||||
template< typename SchedAlgo, typename ... Args >
|
||||
void use_scheduling_algorithm( Args && ... args);
|
||||
std::size_t ready_fibers();
|
||||
|
||||
template< typename Rep, typename Period >
|
||||
@@ -111,6 +112,13 @@ __not_a_fiber__. The fiber object may then safely be destroyed.
|
||||
|
||||
boost::fibers::fiber( some_fn).detach();
|
||||
|
||||
__boost_fiber__ provides a number of ways to wait for a running fiber to
|
||||
complete. You can coordinate even with a detached fiber using a [class_link
|
||||
mutex], or [class_link condition_variable], or any of the other [link
|
||||
synchronization synchronization objects] provided by the library.
|
||||
|
||||
If a detached fiber is still running when the thread's main fiber terminates,
|
||||
that fiber will be [link interruption interrupted] and shut down.
|
||||
|
||||
[heading Joining]
|
||||
|
||||
@@ -277,7 +285,8 @@ operators on __fiber_id__ yield a total order for every non-equal __fiber_id__.
|
||||
|
||||
void swap( fiber & l, fiber & r) noexcept;
|
||||
|
||||
void set_scheduling_algorithm( sched_algorithm * al)
|
||||
template< typename SchedAlgo, typename ... Args >
|
||||
void use_scheduling_algorithm( Args && ... args);
|
||||
|
||||
std::size_t ready_fibers();
|
||||
|
||||
@@ -429,14 +438,13 @@ interruption enabled.]]
|
||||
|
||||
[variablelist
|
||||
[[Preconditions:] [`*this` refers to a fiber of execution. [function_link
|
||||
set_scheduling_algorithm] has been called from this thread with a pointer to a
|
||||
(subclass) instance of [template_link sched_algorithm_with_properties] with the
|
||||
same template argument `PROPS`. `*this` has been scheduled for execution at
|
||||
least once.]]
|
||||
use_scheduling_algorithm] has been called from this thread with a subclass of
|
||||
[template_link sched_algorithm_with_properties] with the same template
|
||||
argument `PROPS`. `*this` has been scheduled for execution at least once.]]
|
||||
[[Returns:] [a reference to the scheduler properties instance for `*this`.]]
|
||||
[[Throws:] [`std::bad_cast` if `set_scheduling_algorithm()` was passed a
|
||||
pointer to a `sched_algorithm_with_properties` subclass with some other
|
||||
template parameter than `PROPS`.]]
|
||||
[[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a
|
||||
`sched_algorithm_with_properties` subclass with some other template parameter
|
||||
than `PROPS`.]]
|
||||
[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a
|
||||
user-coded scheduler to associate extended properties, such as priority, with
|
||||
a fiber instance. This method allows access to those user-provided properties
|
||||
@@ -489,24 +497,21 @@ prior to the call.]]
|
||||
[[Effects:] [Same as `l.swap( r)`.]]
|
||||
]
|
||||
|
||||
[function_heading set_scheduling_algorithm]
|
||||
[function_heading use_scheduling_algorithm]
|
||||
|
||||
void set_scheduling_algorithm( sched_algorithm* scheduler );
|
||||
template< typename SchedAlgo, typename ... Args >
|
||||
void use_scheduling_algorithm( Args && ... args);
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Directs __boost_fiber__ to use `scheduler`, which must be a
|
||||
[[Effects:] [Directs __boost_fiber__ to use `SchedAlgo`, which must be a
|
||||
concrete subclass of __algo__, as the scheduling algorithm for all fibers in
|
||||
the current thread.]]
|
||||
the current thread. Pass any required `SchedAlgo` constructor arguments as
|
||||
`args`.]]
|
||||
[[Note:] [If you want a given thread to use a non-default scheduling
|
||||
algorithm, make that thread call `set_scheduling_algorithm()` before any other
|
||||
algorithm, make that thread call `use_scheduling_algorithm()` before any other
|
||||
__boost_fiber__ entry point. If no scheduler has been set for the current
|
||||
thread by the time __boost_fiber__ needs to use it, the library will
|
||||
create a default [class_link round_robin] instance for this thread.]]
|
||||
[[Note:] [`set_scheduling_algorithm()` does ['not] take ownership of the
|
||||
passed `sched_algorithm*`: __boost_fiber__ does not claim responsibility for the
|
||||
lifespan of the referenced `scheduler` object. The caller must eventually
|
||||
destroy the passed `scheduler`, just as it must allocate it in the first
|
||||
place.]]
|
||||
[[Throws:] [Nothing]]
|
||||
[[See also:] [[link scheduling Scheduling], [link custom Customization]]]
|
||||
]
|
||||
@@ -744,14 +749,14 @@ to run.]]
|
||||
PROPS & properties();
|
||||
|
||||
[variablelist
|
||||
[[Preconditions:] [[function_link set_scheduling_algorithm] has been called
|
||||
from this thread with a pointer to a (subclass) instance of [template_link
|
||||
[[Preconditions:] [[function_link use_scheduling_algorithm] has been called
|
||||
from this thread with a subclass of [template_link
|
||||
sched_algorithm_with_properties] with the same template argument `PROPS`.]]
|
||||
[[Returns:] [a reference to the scheduler properties instance for the
|
||||
currently running fiber.]]
|
||||
[[Throws:] [`std::bad_cast` if `set_scheduling_algorithm()` was passed a
|
||||
pointer to a `sched_algorithm_with_properties` subclass with some other
|
||||
template parameter than `PROPS`.]]
|
||||
[[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a
|
||||
`sched_algorithm_with_properties` subclass with some other template parameter
|
||||
than `PROPS`.]]
|
||||
[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a
|
||||
user-coded scheduler to associate extended properties, such as priority, with
|
||||
a fiber instance. This function allows access to those user-provided
|
||||
|
||||
@@ -129,10 +129,22 @@ After construction [^[post_valid] == other.valid()]]]
|
||||
[variablelist
|
||||
[[Effects:] [Destroys the [xfuture]; ownership is abandoned[end]]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [[`~[xfuture]()] does ['not] block the calling fiber.]]
|
||||
]
|
||||
]
|
||||
[future_dtor_variablelist future .]
|
||||
|
||||
Consider a sequence such as:
|
||||
|
||||
# instantiate [template_link promise]
|
||||
# obtain its `future<>` via [member_link promise..get_future]
|
||||
# launch [class_link fiber], capturing `promise<>`
|
||||
# destroy `future<>`
|
||||
# call [member_link promise..set_value]
|
||||
|
||||
The final `set_value()` call succeeds, but the value is silently discarded: no
|
||||
additional `future<>` can be obtained from that `promise<>`.
|
||||
|
||||
[operator_heading future..operator_assign..operator=]
|
||||
|
||||
future & operator=( future && other) noexcept;
|
||||
|
||||
@@ -18,27 +18,31 @@ synchronization, capable of synchronizing fibers running on different threads.
|
||||
The columns labeled [*fiber (raw)] were compiled with [link cross_thread_sync
|
||||
`BOOST_FIBERS_NO_ATOMICS`].
|
||||
|
||||
[table [@../../performance/overhead_join.cpp Overhead of creating and joining]
|
||||
[table Overhead of creating and joining
|
||||
[[thread] [fiber (atomics)] [fiber (raw)] [tbb] [qthread]]
|
||||
[[31 \u00b5s] [1.1 \u00b5s] [955 ns] [570 ns] [620 ns]]
|
||||
]
|
||||
(from [@../../performance/overhead_join.cpp overhead_join.cpp])
|
||||
|
||||
[table [@../../performance/overhead_detach.cpp Overhead of detach]
|
||||
[table Overhead of detach
|
||||
[[thread] [fiber (atomics)] [fiber (raw)]]
|
||||
[[20 \u00b5s] [3.2 \u00b5s] [3.2 \u00b5s]]
|
||||
]
|
||||
(from [@../../performance/overhead_detach.cpp overhead_detach.cpp])
|
||||
|
||||
[table [@../../performance/overhead_yield.cpp Overhead of yield]
|
||||
[table Overhead of yield
|
||||
[[thread] [fiber (atomics)] [fiber (raw)]]
|
||||
[[38 \u00b5s] [1.3 \u00b5s] [1.1 \u00b5s]]
|
||||
]
|
||||
(from [@../../performance/overhead_yield.cpp overhead_yield.cpp])
|
||||
|
||||
[table [@../../performance/overhead_future.cpp Overhead of waiting on a future]
|
||||
[table Overhead of waiting on a future
|
||||
[[thread] [fiber (atomics)] [fiber (raw)]]
|
||||
[[32 \u00b5s] [3.0 \u00b5s] [2.4 \u00b5s]]
|
||||
]
|
||||
(from [@../../performance/overhead_future.cpp overhead_future.cpp])
|
||||
|
||||
[table [@../../performance/scale_join.cpp Scaling of creating and joining]
|
||||
[table Scaling of creating and joining
|
||||
[[average of] [thread] [fiber (atomics)] [fiber (raw)]]
|
||||
[[10] [50.65 \u00b5s] [4.83 \u00b5s] [3.76 \u00b5s]]
|
||||
[[50] [52.99 \u00b5s] [4.84 \u00b5s] [2.78 \u00b5s]]
|
||||
@@ -48,6 +52,6 @@ The columns labeled [*fiber (raw)] were compiled with [link cross_thread_sync
|
||||
[[5000] [42.30 \u00b5s] [5.07 \u00b5s] [4.57 \u00b5s]]
|
||||
[[10000] [41.07 \u00b5s] [5.12 \u00b5s] [4.21 \u00b5s]]
|
||||
]
|
||||
|
||||
(from [@../../performance/scale_join.cpp scale_join.cpp])
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -20,13 +20,12 @@ customization point. (See [link custom Customization].)
|
||||
Each thread has its own scheduler. By default, __boost_fiber__ implicitly
|
||||
instantiates [class_link round_robin] as the scheduler for each thread.
|
||||
|
||||
You are explicitly permitted to code your own __algo__ subclass, and to pass
|
||||
it to [function_link set_scheduling_algorithm].
|
||||
You are explicitly permitted to code your own __algo__ subclass, and to
|
||||
specify it to [function_link use_scheduling_algorithm].
|
||||
|
||||
|
||||
void thread_fn() {
|
||||
my_fiber_scheduler mfs;
|
||||
boost::fibers::set_scheduling_algorithm( & mfs);
|
||||
boost::fibers::use_scheduling_algorithm<my_fiber_scheduler>();
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ This function will feature in the example calls to the various functions
|
||||
presented below.
|
||||
|
||||
[section when_any]
|
||||
[#wait_first_simple_section]
|
||||
[section when_any, simple completion]
|
||||
|
||||
The simplest case is when you only need to know that the first of a set of
|
||||
|
||||
Reference in New Issue
Block a user