mirror of
https://github.com/boostorg/fiber.git
synced 2026-07-21 13:13:32 +00:00
move sched_algorithm to algo::algorithm
- new namesapce algo - shared_round_robin with shared ready queue
This commit is contained in:
+3
-2
@@ -27,7 +27,9 @@ project boost/fiber
|
||||
;
|
||||
|
||||
lib boost_fiber
|
||||
: algorithm.cpp
|
||||
: algo/algorithm.cpp
|
||||
algo/round_robin.cpp
|
||||
algo/shared_round_robin.cpp
|
||||
barrier.cpp
|
||||
condition_variable.cpp
|
||||
context.cpp
|
||||
@@ -38,7 +40,6 @@ lib boost_fiber
|
||||
properties.cpp
|
||||
recursive_mutex.cpp
|
||||
recursive_timed_mutex.cpp
|
||||
round_robin.cpp
|
||||
timed_mutex.cpp
|
||||
scheduler.cpp
|
||||
: <link>shared:<library>../../context/build//boost_context
|
||||
|
||||
+13
-8
@@ -48,17 +48,22 @@ members in the barrier object.]
|
||||
|
||||
[class_heading barrier]
|
||||
|
||||
#include <boost/fiber/barrier.hpp>
|
||||
#include <boost/fiber/barrier.hpp>
|
||||
|
||||
class barrier {
|
||||
public:
|
||||
explicit barrier( std::size_t);
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
barrier( barrier const&) = delete;
|
||||
barrier & operator=( barrier const&) = delete;
|
||||
class barrier {
|
||||
public:
|
||||
explicit barrier( std::size_t);
|
||||
|
||||
bool wait();
|
||||
};
|
||||
barrier( barrier const&) = delete;
|
||||
barrier & operator=( barrier const&) = delete;
|
||||
|
||||
bool wait();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
+75
-65
@@ -73,35 +73,40 @@ channel operations return the state of the channel.
|
||||
|
||||
[template_heading unbounded_channel]
|
||||
|
||||
#include <boost/fiber/unbounded_channel.hpp>
|
||||
#include <boost/fiber/unbounded_channel.hpp>
|
||||
|
||||
template< typename T, typename __Allocator__ = __allocator__ >
|
||||
class unbounded_channel {
|
||||
public:
|
||||
typedef T value_type;
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept;
|
||||
template< typename T, typename __Allocator__ = __allocator__ >
|
||||
class unbounded_channel {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
unbounded_channel( unbounded_channel const& other) = delete;
|
||||
unbounded_channel & operator=( unbounded_channel const& other) = delete;
|
||||
explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept;
|
||||
|
||||
void close() noexcept;
|
||||
unbounded_channel( unbounded_channel const& other) = delete;
|
||||
unbounded_channel & operator=( unbounded_channel const& other) = delete;
|
||||
|
||||
channel_op_status push( value_type const& va);
|
||||
channel_op_status push( value_type && va);
|
||||
void close() noexcept;
|
||||
|
||||
channel_op_status pop( value_type & va);
|
||||
value_type value_pop();
|
||||
channel_op_status try_pop( value_type & va);
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status pop_wait_for(
|
||||
value_type & va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status pop_wait_until(
|
||||
value_type & va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
};
|
||||
channel_op_status push( value_type const& va);
|
||||
channel_op_status push( value_type && va);
|
||||
|
||||
channel_op_status pop( value_type & va);
|
||||
value_type value_pop();
|
||||
channel_op_status try_pop( value_type & va);
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status pop_wait_for(
|
||||
value_type & va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status pop_wait_until(
|
||||
value_type & va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
@@ -234,55 +239,60 @@ time as (system time + `timeout_duration`).
|
||||
|
||||
[template_heading bounded_channel]
|
||||
|
||||
#include <boost/fiber/bounded_channel.hpp>
|
||||
#include <boost/fiber/bounded_channel.hpp>
|
||||
|
||||
template< typename T, typename __Allocator__ = __allocator__ >
|
||||
class bounded_channel {
|
||||
public:
|
||||
typedef T value_type;
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() );
|
||||
bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() );
|
||||
template< typename T, typename __Allocator__ = __allocator__ >
|
||||
class bounded_channel {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
bounded_channel( bounded_channel const& other) = delete;
|
||||
bounded_channel & operator=( bounded_channel const& other) = delete;
|
||||
bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() );
|
||||
bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() );
|
||||
|
||||
std::size_t upper_bound() const noexcept;
|
||||
std::size_t lower_bound() const noexcept;
|
||||
bounded_channel( bounded_channel const& other) = delete;
|
||||
bounded_channel & operator=( bounded_channel const& other) = delete;
|
||||
|
||||
void close() noexcept;
|
||||
std::size_t upper_bound() const noexcept;
|
||||
std::size_t lower_bound() const noexcept;
|
||||
|
||||
channel_op_status push( value_type const& va);
|
||||
channel_op_status push( value_type && va);
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status push_wait_for(
|
||||
value_type const& va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
channel_op_status push_wait_for( value_type && va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status push_wait_until(
|
||||
value_type const& va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status push_wait_until(
|
||||
value_type && va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
channel_op_status try_push( value_type const& va);
|
||||
channel_op_status try_push( value_type && va);
|
||||
void close() noexcept;
|
||||
|
||||
channel_op_status pop( value_type & va);
|
||||
value_type value_pop();
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status pop_wait_for(
|
||||
value_type & va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status pop_wait_until(
|
||||
value_type & va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
channel_op_status try_pop( value_type & va);
|
||||
};
|
||||
channel_op_status push( value_type const& va);
|
||||
channel_op_status push( value_type && va);
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status push_wait_for(
|
||||
value_type const& va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
channel_op_status push_wait_for( value_type && va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status push_wait_until(
|
||||
value_type const& va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status push_wait_until(
|
||||
value_type && va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
channel_op_status try_push( value_type const& va);
|
||||
channel_op_status try_push( value_type && va);
|
||||
|
||||
channel_op_status pop( value_type & va);
|
||||
value_type value_pop();
|
||||
template< typename Rep, typename Period >
|
||||
channel_op_status pop_wait_for(
|
||||
value_type & va,
|
||||
std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
template< typename Clock, typename Duration >
|
||||
channel_op_status pop_wait_until(
|
||||
value_type & va,
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time);
|
||||
channel_op_status try_pop( value_type & va);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
|
||||
+32
-27
@@ -156,42 +156,47 @@ A timed wait operation might return because of timeout or not.
|
||||
[template condition_variable_x[classname locktype template_rtype template_arg]
|
||||
[class_heading [classname]]
|
||||
|
||||
#include <boost/fiber/condition_variable.hpp>
|
||||
#include <boost/fiber/condition_variable.hpp>
|
||||
|
||||
class ``[classname]`` {
|
||||
public:
|
||||
``[classname]``();
|
||||
~``[classname]``();
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
``[classname]``( ``[classname]`` const&) = delete;
|
||||
``[classname]`` & operator=( ``[classname]`` const&) = delete;
|
||||
class ``[classname]`` {
|
||||
public:
|
||||
``[classname]``();
|
||||
~``[classname]``();
|
||||
|
||||
void notify_one() noexcept;
|
||||
void notify_all() noexcept;
|
||||
``[classname]``( ``[classname]`` const&) = delete;
|
||||
``[classname]`` & operator=( ``[classname]`` const&) = delete;
|
||||
|
||||
``[template_rtype]`` wait( ``[locktype]`` &);
|
||||
void notify_one() noexcept;
|
||||
void notify_all() noexcept;
|
||||
|
||||
template< ``[template_arg]`` Pred >
|
||||
void wait( ``[locktype]`` &, Pred);
|
||||
``[template_rtype]`` wait( ``[locktype]`` &);
|
||||
|
||||
template< ``[template_arg]`` Clock, typename Duration >
|
||||
cv_status wait_until( ``[locktype]`` &,
|
||||
std::chrono::time_point< Clock, Duration > const&);
|
||||
template< ``[template_arg]`` Pred >
|
||||
void wait( ``[locktype]`` &, Pred);
|
||||
|
||||
template< ``[template_arg]`` Clock, typename Duration, typename Pred >
|
||||
bool wait_until( ``[locktype]`` &,
|
||||
std::chrono::time_point< Clock, Duration > const&,
|
||||
Pred);
|
||||
template< ``[template_arg]`` Clock, typename Duration >
|
||||
cv_status wait_until( ``[locktype]`` &,
|
||||
std::chrono::time_point< Clock, Duration > const&);
|
||||
|
||||
template< ``[template_arg]`` Rep, typename Period >
|
||||
cv_status wait_for( ``[locktype]`` &,
|
||||
std::chrono::duration< Rep, Period > const&);
|
||||
template< ``[template_arg]`` Clock, typename Duration, typename Pred >
|
||||
bool wait_until( ``[locktype]`` &,
|
||||
std::chrono::time_point< Clock, Duration > const&,
|
||||
Pred);
|
||||
|
||||
template< ``[template_arg]`` Rep, typename Period, typename Pred >
|
||||
bool wait_for( ``[locktype]`` &,
|
||||
std::chrono::duration< Rep, Period > const&,
|
||||
Pred);
|
||||
};
|
||||
template< ``[template_arg]`` Rep, typename Period >
|
||||
cv_status wait_for( ``[locktype]`` &,
|
||||
std::chrono::duration< Rep, Period > const&);
|
||||
|
||||
template< ``[template_arg]`` Rep, typename Period, typename Pred >
|
||||
bool wait_for( ``[locktype]`` &,
|
||||
std::chrono::duration< Rep, Period > const&,
|
||||
Pred);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
|
||||
@@ -72,13 +72,13 @@ fiber_properties].
|
||||
[heading Custom Scheduler Class]
|
||||
|
||||
Now we can derive a custom scheduler from [template_link
|
||||
sched_algorithm_with_properties], specifying our custom property class
|
||||
algorithm_with_properties], specifying our custom property class
|
||||
`priority_props` as the template parameter.
|
||||
|
||||
[priority_scheduler]
|
||||
|
||||
Our example `priority_scheduler` doesn't override [member_link
|
||||
sched_algorithm_with_properties..new_properties]: we're content with
|
||||
algorithm_with_properties..new_properties]: we're content with
|
||||
allocating `priority_props` instances on the heap.
|
||||
|
||||
[heading Replace Default Scheduler]
|
||||
@@ -114,6 +114,6 @@ until it blocks (or yields, or terminates) for some other reason. As shown in
|
||||
the `launch()` function above, it is reasonable to launch a fiber and
|
||||
immediately set relevant properties -- such as, for instance, its priority.
|
||||
Your custom scheduler can then make use of this information next time the
|
||||
fiber manager calls [member_link sched_algorithm_with_properties..pick_next].
|
||||
fiber manager calls [member_link algorithm_with_properties..pick_next].
|
||||
|
||||
[endsect]
|
||||
|
||||
+49
-10
@@ -20,14 +20,18 @@
|
||||
bool operator<( fiber const& l, fiber const& r) noexcept;
|
||||
void swap( fiber & l, fiber & r) noexcept;
|
||||
|
||||
struct sched_algorithm;
|
||||
template< typename PROPS >
|
||||
struct sched_algorithm_with_properties;
|
||||
class round_robin;
|
||||
template< typename SchedAlgo, typename ... Args >
|
||||
void use_scheduling_algorithm( Args && ... args);
|
||||
bool has_ready_fibers();
|
||||
|
||||
namespace algo {
|
||||
|
||||
struct algorithm;
|
||||
template< typename PROPS >
|
||||
struct algorithm_with_properties;
|
||||
class round_robin;
|
||||
class shared_round_robin;
|
||||
|
||||
}
|
||||
|
||||
namespace this_fiber {
|
||||
@@ -195,6 +199,9 @@ be entered when the fiber scheduler has a chance to resume it later.]]
|
||||
|
||||
#include <boost/fiber/fiber.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class fiber {
|
||||
public:
|
||||
class id;
|
||||
@@ -246,6 +253,8 @@ be entered when the fiber scheduler has a chance to resume it later.]]
|
||||
|
||||
bool has_ready_fibers() noexcept;
|
||||
|
||||
}}
|
||||
|
||||
|
||||
[heading Default constructor]
|
||||
|
||||
@@ -385,13 +394,13 @@ default-constructed __fiber_id__.]]
|
||||
[variablelist
|
||||
[[Preconditions:] [`*this` refers to a fiber of execution. [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
|
||||
[template_link algorithm_with_properties] with the same template
|
||||
argument `PROPS`.]]
|
||||
[[Returns:] [a reference to the scheduler properties instance for `*this`.]]
|
||||
[[Throws:] [`std::bad_cast` if `use_scheduling_algorithm()` was called with a
|
||||
`sched_algorithm_with_properties` subclass with some other template parameter
|
||||
`algorithm_with_properties` subclass with some other template parameter
|
||||
than `PROPS`.]]
|
||||
[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a
|
||||
[[Note:] [[template_link 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.]]
|
||||
[[See also:] [[link custom Customization]]]
|
||||
@@ -466,6 +475,9 @@ create a default [class_link round_robin] instance for this thread.]]
|
||||
|
||||
#include <boost/fiber/fiber.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class id {
|
||||
public:
|
||||
constexpr id() noexcept;
|
||||
@@ -487,6 +499,8 @@ create a default [class_link round_robin] instance for this thread.]]
|
||||
operator<<( std::basic_ostream< charT, traitsT > &, id const&);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
constexpr id() noexcept;
|
||||
@@ -596,8 +610,13 @@ explicitly-launched fiber.
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
fiber::id get_id() noexcept;
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[Returns:] [An instance of __fiber_id__ that represents the currently
|
||||
executing fiber.]]
|
||||
@@ -608,9 +627,14 @@ executing fiber.]]
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename Clock, typename Duration >
|
||||
void sleep_until( std::chrono::time_point< Clock, Duration > const& abs_time);
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Suspends the current fiber until the time point specified by
|
||||
`abs_time` has been reached.]]
|
||||
@@ -628,9 +652,14 @@ exceptions are referred to as ['timeout-related exceptions.]]]]
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< class Rep, class Period >
|
||||
void sleep_for( std::chrono::duration< Rep, Period > const& rel_time);
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Suspends the current fiber until the time duration specified by
|
||||
`rel_time` has elapsed.]]
|
||||
@@ -643,8 +672,13 @@ there are no guarantees about how soon after that it might resume.]]
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
void yield() noexcept;
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Reliquishes execution control, allowing other fibers to run.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
@@ -657,19 +691,24 @@ to run.]]
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename PROPS >
|
||||
PROPS & properties();
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[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`.]]
|
||||
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 `use_scheduling_algorithm()` was called with a
|
||||
`sched_algorithm_with_properties` subclass with some other template parameter
|
||||
`algorithm_with_properties` subclass with some other template parameter
|
||||
than `PROPS`.]]
|
||||
[[Note:] [[template_link sched_algorithm_with_properties] provides a way for a
|
||||
[[Note:] [[template_link 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
|
||||
properties.]]
|
||||
|
||||
+3
-3
@@ -144,9 +144,9 @@
|
||||
[def __already_retrieved__ `future_errc::future_already_retrieved`]
|
||||
[def __already_satisfied__ `future_errc::future_already_satisfied`]
|
||||
|
||||
[def __algo__ [class_link sched_algorithm]]
|
||||
[def __algo_awakened__ [member_link sched_algorithm..awakened]]
|
||||
[def __algo_pick_next__ [member_link sched_algorithm..pick_next]]
|
||||
[def __algo__ [class_link algorithm]]
|
||||
[def __algo_awakened__ [member_link algorithm..awakened]]
|
||||
[def __algo_pick_next__ [member_link algorithm..pick_next]]
|
||||
[def __async__ `async()`]
|
||||
[def __barrier_wait__ [member_link barrier..wait]]
|
||||
[def __cond_wait_for__ [member_link condition_variable..wait_for]]
|
||||
|
||||
@@ -26,6 +26,9 @@ order.
|
||||
|
||||
#include <boost/fiber/fss.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename T >
|
||||
class fiber_specific_ptr {
|
||||
public:
|
||||
@@ -51,6 +54,8 @@ order.
|
||||
void reset( T *);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
fiber_specific_ptr();
|
||||
|
||||
@@ -55,6 +55,11 @@ Timed wait-operations (__wait_for__ and __wait_until__) return the state of the
|
||||
|
||||
A __future__ contains a [link shared_state shared state] which is not shared with any other future.
|
||||
|
||||
#include <boost/fiber/future/future.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename R >
|
||||
class future {
|
||||
public:
|
||||
@@ -91,6 +96,8 @@ A __future__ contains a [link shared_state shared state] which is not shared wit
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time) const;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Default constructor]
|
||||
|
||||
future() noexcept;
|
||||
@@ -257,6 +264,11 @@ timeout-related exceptions.]]
|
||||
A __shared_future__ contains a [link shared_state shared state] which might be
|
||||
shared with other __shared_future__ instances.
|
||||
|
||||
#include <boost/fiber/future/future.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename R >
|
||||
class shared_future {
|
||||
public:
|
||||
@@ -295,6 +307,8 @@ shared with other __shared_future__ instances.
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time) const;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Default constructor]
|
||||
|
||||
shared_future();
|
||||
@@ -352,6 +366,9 @@ const&`, otherwise `false`.]]
|
||||
|
||||
#include <boost/fiber/future/async.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< class Function, class ... Args >
|
||||
future<
|
||||
std::result_of_t<
|
||||
@@ -377,6 +394,8 @@ const&`, otherwise `false`.]]
|
||||
async( ``[link class_launch `launch`]`` policy, __allocator_arg_t__, __StackAllocator__ salloc,
|
||||
Function && fn, Args && ... args);
|
||||
|
||||
}}
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Executes `fn` in a [class_link fiber] and returns an associated
|
||||
[template_link future].]]
|
||||
|
||||
+3
-3
@@ -69,7 +69,7 @@ wake up again on its next expiration.
|
||||
Since, in this thought experiment, we always pass control to the fiber manager
|
||||
via `yield()`, the calling fiber is never blocked. Therefore there is always
|
||||
at least one ready fiber. Therefore the fiber manager never calls [member_link
|
||||
sched_algorithm..suspend_until].
|
||||
algorithm..suspend_until].
|
||||
|
||||
Using
|
||||
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html
|
||||
@@ -247,7 +247,7 @@ Doubtless you have been asking yourself: why are we calling
|
||||
`suspend_until()`, whose very API was designed for just such a purpose?
|
||||
|
||||
Under normal circumstances, when the fiber manager finds no ready fibers, it
|
||||
calls [member_link sched_algorithm..suspend_until]. Why test
|
||||
calls [member_link algorithm..suspend_until]. Why test
|
||||
`has_ready_fibers()` in the lambda loop? Why not leverage the normal
|
||||
mechanism?
|
||||
|
||||
@@ -257,7 +257,7 @@ Consider the lambda loop shown above. The only __boost_fiber__ APIs it engages
|
||||
are `has_ready_fibers()` and [ns_function_link this_fiber..yield]. `yield()`
|
||||
does not ['block] the calling fiber: the calling fiber does not become
|
||||
unready. It is immediately passed back to [member_link
|
||||
sched_algorithm..awakened], to be resumed in its turn when all other ready
|
||||
algorithm..awakened], to be resumed in its turn when all other ready
|
||||
fibers have had a chance to run. In other words: during a `yield()` call,
|
||||
['there is always at least one ready fiber.]
|
||||
|
||||
|
||||
+2
-2
@@ -43,12 +43,12 @@ which the fiber migrates.
|
||||
|
||||
Thus, fiber migration is accomplished by sharing state between instances of a
|
||||
user-coded __algo__ implementation running on different threads. The fiber[s]
|
||||
original thread calls [member_link sched_algorithm..awakened], passing the
|
||||
original thread calls [member_link algorithm..awakened], passing the
|
||||
fiber[s] [class_link context][^*]. The `awakened()` implementation calls
|
||||
__context_detach__.
|
||||
|
||||
At some later point, when the same or a different thread calls [member_link
|
||||
sched_algorithm..pick_next], the `pick_next()` implementation selects a ready
|
||||
algorithm..pick_next], the `pick_next()` implementation selects a ready
|
||||
fiber and calls __context_attach__ on it before returning it.
|
||||
|
||||
As stated above, a `context` for which `is_context(pinned_context) == true`
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
[class_heading mutex]
|
||||
|
||||
#include <boost/fiber/mutex.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class mutex {
|
||||
public:
|
||||
@@ -25,6 +28,8 @@
|
||||
void unlock();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
__mutex__ provides an exclusive-ownership mutex. At most one fiber can own the
|
||||
lock on a given instance of __mutex__ at any time. Multiple concurrent calls to
|
||||
__lock__, __try_lock__ and __unlock__ shall be permitted.
|
||||
@@ -76,6 +81,9 @@ otherwise.]]
|
||||
|
||||
#include <boost/fiber/timed_mutex.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class timed_mutex {
|
||||
public:
|
||||
timed_mutex();
|
||||
@@ -94,6 +102,8 @@ otherwise.]]
|
||||
bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
__timed_mutex__ provides an exclusive-ownership mutex. At most one fiber can own
|
||||
the lock on a given instance of __timed_mutex__ at any time. Multiple concurrent
|
||||
calls to __lock__, __try_lock__, __try_lock_until__, __try_lock_for__ and
|
||||
@@ -177,6 +187,9 @@ otherwise.]]
|
||||
|
||||
#include <boost/fiber/recursive_mutex.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class recursive_mutex {
|
||||
public:
|
||||
recursive_mutex();
|
||||
@@ -190,6 +203,8 @@ otherwise.]]
|
||||
void unlock();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
__recursive_mutex__ provides an exclusive-ownership recursive mutex. At most one
|
||||
fiber can own the lock on a given instance of __recursive_mutex__ at any time.
|
||||
Multiple concurrent calls to __lock__, __try_lock__ and __unlock__ shall be
|
||||
@@ -236,6 +251,9 @@ otherwise.]]
|
||||
|
||||
#include <boost/fiber/recursive_timed_mutex.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class recursive_timed_mutex {
|
||||
public:
|
||||
recursive_timed_mutex();
|
||||
@@ -254,6 +272,8 @@ otherwise.]]
|
||||
bool try_lock_for( std::chrono::duration< Rep, Period > const& timeout_duration);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
__recursive_timed_mutex__ provides an exclusive-ownership recursive mutex. At
|
||||
most one fiber can own the lock on a given instance of
|
||||
__recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock__,
|
||||
|
||||
@@ -26,6 +26,11 @@ Conventional usage of `packaged_task<>` is like this:
|
||||
This is, in fact, pretty much what [ns_function_link fibers..async]
|
||||
encapsulates.
|
||||
|
||||
#include <boost/fiber/future/packaged_task.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< class R, typename ... Args >
|
||||
class packaged_task< R( Args ... ) > {
|
||||
public:
|
||||
@@ -61,6 +66,8 @@ encapsulates.
|
||||
template< typename Signature >
|
||||
void swap( packaged_task< Signature > &, packaged_task< Signature > &) noexcept;
|
||||
|
||||
}}
|
||||
|
||||
[heading Default constructor `packaged_task()`]
|
||||
|
||||
packaged_task() noexcept;
|
||||
|
||||
@@ -12,6 +12,11 @@ A __promise__ provides a mechanism to store a value (or exception) that can
|
||||
later be retrieved from the corresponding __future__ object. `promise<>` and
|
||||
`future<>` communicate via their underlying [link shared_state shared state].
|
||||
|
||||
#include <boost/fiber/future/promise.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
template< typename R >
|
||||
class promise {
|
||||
public:
|
||||
@@ -45,6 +50,8 @@ later be retrieved from the corresponding __future__ object. `promise<>` and
|
||||
template< typename R >
|
||||
void swap( promise< R > &, promise< R > &) noexcept;
|
||||
|
||||
}
|
||||
|
||||
[heading Default constructor]
|
||||
|
||||
promise();
|
||||
|
||||
+90
-62
@@ -22,12 +22,12 @@ different schedulers. 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. For the most
|
||||
part, your `sched_algorithm` subclass need not defend against cross-thread
|
||||
part, your `algorithm` subclass need not defend against cross-thread
|
||||
calls: the fiber manager intercepts and defers such calls. Most
|
||||
`sched_algorithm` methods are only ever directly called from the thread whose
|
||||
`algorithm` methods are only ever directly called from the thread whose
|
||||
fibers it is managing [mdash] with exceptions as documented below.
|
||||
|
||||
Your `sched_algorithm` subclass is engaged on a particular thread by calling
|
||||
Your `algorithm` subclass is engaged on a particular thread by calling
|
||||
[function_link use_scheduling_algorithm]:
|
||||
|
||||
void thread_fn() {
|
||||
@@ -39,15 +39,19 @@ A scheduler class must implement interface __algo__. __boost_fiber__ provides
|
||||
one scheduler: [class_link round_robin].
|
||||
|
||||
|
||||
[class_heading sched_algorithm]
|
||||
[class_heading algorithm]
|
||||
|
||||
`sched_algorithm` is the abstract base class defining the interface that a
|
||||
`algorithm` is the abstract base class defining the interface that a
|
||||
fiber scheduler must implement.
|
||||
|
||||
#include <boost/fiber/algorithm.hpp>
|
||||
#include <boost/fiber/algo/algorithm.hpp>
|
||||
|
||||
struct sched_algorithm {
|
||||
virtual ~sched_algorithm();
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
struct algorithm {
|
||||
virtual ~algorithm();
|
||||
|
||||
virtual void awakened( context *) noexcept = 0;
|
||||
|
||||
@@ -60,7 +64,9 @@ fiber scheduler must implement.
|
||||
virtual void notify() noexcept = 0;
|
||||
};
|
||||
|
||||
[member_heading sched_algorithm..awakened]
|
||||
}}}
|
||||
|
||||
[member_heading algorithm..awakened]
|
||||
|
||||
virtual void awakened( context * f) noexcept = 0;
|
||||
|
||||
@@ -74,7 +80,7 @@ queue.]]
|
||||
[[See also:] [[class_link round_robin]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm..pick_next]
|
||||
[member_heading algorithm..pick_next]
|
||||
|
||||
virtual context * pick_next() noexcept = 0;
|
||||
|
||||
@@ -87,7 +93,7 @@ queue.]]
|
||||
[[See also:] [[class_link round_robin]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm..has_ready_fibers]
|
||||
[member_heading algorithm..has_ready_fibers]
|
||||
|
||||
virtual bool has_ready_fibers() const noexcept = 0;
|
||||
|
||||
@@ -95,7 +101,7 @@ queue.]]
|
||||
[[Returns:] [`true` if scheduler has fibers ready to run.]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm..suspend_until]
|
||||
[member_heading algorithm..suspend_until]
|
||||
|
||||
virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0;
|
||||
|
||||
@@ -105,7 +111,7 @@ time-point `abs_time`.]]
|
||||
[[Note:] [This method allows a custom scheduler to yield control to the
|
||||
containing environment in whatever way makes sense. The fiber manager is
|
||||
stating that `suspend_until()` need not return until `abs_time` [mdash] or
|
||||
[member_link sched_algorithm..notify] is called [mdash] whichever comes first.
|
||||
[member_link algorithm..notify] is called [mdash] whichever comes first.
|
||||
The interaction with `notify()` means that, for instance, calling
|
||||
[@http://en.cppreference.com/w/cpp/thread/sleep_until
|
||||
`std::this_thread::sleep_until(abs_time)`] would be too simplistic.
|
||||
@@ -115,29 +121,33 @@ The interaction with `notify()` means that, for instance, calling
|
||||
round_robin..notify].]]
|
||||
[[Note:] [Given that `notify()` might be called from another thread, your
|
||||
`suspend_until()` implementation [mdash] like the rest of your
|
||||
`sched_algorithm` implementation [mdash] must guard any data it shares with
|
||||
`algorithm` implementation [mdash] must guard any data it shares with
|
||||
your `notify()` implementation.]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm..notify]
|
||||
[member_heading algorithm..notify]
|
||||
|
||||
virtual void notify() noexcept = 0;
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Requests the scheduler to return from a pending call to
|
||||
[member_link sched_algorithm..suspend_until].]]
|
||||
[[Note:] [Alone among the `sched_algorithm` methods, `notify()` may be called
|
||||
[member_link algorithm..suspend_until].]]
|
||||
[[Note:] [Alone among the `algorithm` methods, `notify()` may be called
|
||||
from another thread. Your `notify()` implementation must guard any data it
|
||||
shares with the rest of your `sched_algorithm` implementation.]]
|
||||
shares with the rest of your `algorithm` implementation.]]
|
||||
]
|
||||
|
||||
[class_heading round_robin]
|
||||
|
||||
This class implements __algo__, scheduling fibers in round-robin fashion.
|
||||
|
||||
#include <boost/fiber/round_robin.hpp>
|
||||
#include <boost/fiber/algo/round_robin.hpp>
|
||||
|
||||
class round_robin : public sched_algorithm {
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
class round_robin : public algorithm {
|
||||
virtual void awakened( context *) noexcept;
|
||||
|
||||
virtual context * pick_next() noexcept;
|
||||
@@ -149,6 +159,8 @@ This class implements __algo__, scheduling fibers in round-robin fashion.
|
||||
virtual void notify() noexcept;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
[member_heading round_robin..awakened]
|
||||
|
||||
virtual void awakened( context * f) noexcept;
|
||||
@@ -209,7 +221,7 @@ wakes `suspend_until()` via
|
||||
[heading Custom Scheduler Fiber Properties]
|
||||
|
||||
A scheduler class directly derived from __algo__ can use any information
|
||||
available from [class_link context] to implement the `sched_algorithm`
|
||||
available from [class_link context] to implement the `algorithm`
|
||||
interface. But a custom scheduler might need to track additional properties
|
||||
for a fiber. For instance, a priority-based scheduler would need to track a
|
||||
fiber's priority.
|
||||
@@ -223,6 +235,9 @@ A custom fiber properties class must be derived from `fiber_properties`.
|
||||
|
||||
#include <boost/fiber/properties.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class fiber_properties {
|
||||
public:
|
||||
fiber_properties( context *) noexcept;
|
||||
@@ -233,6 +248,8 @@ A custom fiber properties class must be derived from `fiber_properties`.
|
||||
void notify() noexcept;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
fiber_properties( context * f) noexcept;
|
||||
@@ -250,13 +267,13 @@ to the base-class `fiber_properties` constructor.]]
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Pass control to the custom [template_link
|
||||
sched_algorithm_with_properties] subclass's [member_link
|
||||
sched_algorithm_with_properties..property_change] method.]]
|
||||
algorithm_with_properties] subclass's [member_link
|
||||
algorithm_with_properties..property_change] method.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [A custom scheduler's [member_link
|
||||
sched_algorithm_with_properties..pick_next] method might dynamically select
|
||||
algorithm_with_properties..pick_next] method might dynamically select
|
||||
from the ready fibers, or [member_link
|
||||
sched_algorithm_with_properties..awakened] might instead insert each ready
|
||||
algorithm_with_properties..awakened] might instead insert each ready
|
||||
fiber into some form of ready queue for `pick_next()`. In the latter case, if
|
||||
application code modifies a fiber property (e.g. priority) that should affect
|
||||
that fiber's relationship to other ready fibers, the custom scheduler must be
|
||||
@@ -270,16 +287,20 @@ behavior of the `pick_next()` method, you need not call `notify()` when that
|
||||
property is modified.]]
|
||||
]
|
||||
|
||||
[template_heading sched_algorithm_with_properties]
|
||||
[template_heading algorithm_with_properties]
|
||||
|
||||
A custom scheduler that depends on a custom properties class `PROPS` should be
|
||||
derived from `sched_algorithm_with_properties<PROPS>`. `PROPS` should be
|
||||
derived from `algorithm_with_properties<PROPS>`. `PROPS` should be
|
||||
derived from [class_link fiber_properties].
|
||||
|
||||
#include <boost/fiber/algorithm.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
template< typename PROPS >
|
||||
struct sched_algorithm_with_properties {
|
||||
struct algorithm_with_properties {
|
||||
virtual void awakened( context *, PROPS &) noexcept = 0;
|
||||
|
||||
virtual context * pick_next() noexcept;
|
||||
@@ -297,20 +318,22 @@ derived from [class_link fiber_properties].
|
||||
virtual fiber_properties * new_properties( context *);
|
||||
};
|
||||
|
||||
[member_heading sched_algorithm_with_properties..awakened]
|
||||
}}}
|
||||
|
||||
[member_heading algorithm_with_properties..awakened]
|
||||
|
||||
virtual void awakened( context * f, PROPS & properties) noexcept;
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Informs the scheduler that fiber `f` is ready to run, like
|
||||
[member_link sched_algorithm..awakened]. Passes the fiber's associated `PROPS`
|
||||
[member_link algorithm..awakened]. Passes the fiber's associated `PROPS`
|
||||
instance.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [A `sched_algorithm_with_properties<>` subclass must override this
|
||||
method instead of `sched_algorithm::awakened()`.]]
|
||||
[[Note:] [A `algorithm_with_properties<>` subclass must override this
|
||||
method instead of `algorithm::awakened()`.]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..pick_next]
|
||||
[member_heading algorithm_with_properties..pick_next]
|
||||
|
||||
virtual context * pick_next() noexcept;
|
||||
|
||||
@@ -318,40 +341,40 @@ method instead of `sched_algorithm::awakened()`.]]
|
||||
[[Returns:] [the fiber which is to be resumed next, or `nullptr` if there is no
|
||||
ready fiber.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [same as [member_link sched_algorithm..pick_next]]]
|
||||
[[Note:] [same as [member_link algorithm..pick_next]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..has_ready_fibers]
|
||||
[member_heading algorithm_with_properties..has_ready_fibers]
|
||||
|
||||
virtual bool has_ready_fibers() const noexcept;
|
||||
|
||||
[variablelist
|
||||
[[Returns:] [`true` if scheduler has fibers ready to run.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [same as [member_link sched_algorithm..has_ready_fibers]]]
|
||||
[[Note:] [same as [member_link algorithm..has_ready_fibers]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..suspend_until]
|
||||
[member_heading algorithm_with_properties..suspend_until]
|
||||
|
||||
virtual void suspend_until( std::chrono::steady_clock::time_point const& abs_time) noexcept = 0;
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Informs the scheduler that no fiber will be ready until
|
||||
time-point `abs_time`.]]
|
||||
[[Note:] [same as [member_link sched_algorithm..suspend_until]]]
|
||||
[[Note:] [same as [member_link algorithm..suspend_until]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..notify]
|
||||
[member_heading algorithm_with_properties..notify]
|
||||
|
||||
virtual void notify() noexcept = 0;
|
||||
|
||||
[variablelist
|
||||
[[Effects:] [Requests the scheduler to return from a pending call to
|
||||
[member_link sched_algorithm_with_properties..suspend_until].]]
|
||||
[[Note:] [same as [member_link sched_algorithm..notify]]]
|
||||
[member_link algorithm_with_properties..suspend_until].]]
|
||||
[[Note:] [same as [member_link algorithm..notify]]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..properties]
|
||||
[member_heading algorithm_with_properties..properties]
|
||||
|
||||
PROPS& properties( context * f) noexcept;
|
||||
|
||||
@@ -359,15 +382,15 @@ time-point `abs_time`.]]
|
||||
[[Returns:] [the `PROPS` instance associated with fiber `f`.]]
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Note:] [The fiber's associated `PROPS` instance is already passed to
|
||||
[member_link sched_algorithm_with_properties..awakened] and [member_link
|
||||
sched_algorithm_with_properties..property_change]. However, every [class_link
|
||||
sched_algorithm] subclass is expected to track a collection of ready
|
||||
[member_link algorithm_with_properties..awakened] and [member_link
|
||||
algorithm_with_properties..property_change]. However, every [class_link
|
||||
algorithm] subclass is expected to track a collection of ready
|
||||
[class_link context] instances. This method allows your custom scheduler
|
||||
to retrieve the [class_link fiber_properties] subclass instance for any
|
||||
`context` in its collection.]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..property_change]
|
||||
[member_heading algorithm_with_properties..property_change]
|
||||
|
||||
virtual void property_change( context * f, PROPS & properties) noexcept;
|
||||
|
||||
@@ -381,14 +404,14 @@ fiber_properties] subclass explicitly calls [member_link
|
||||
fiber_properties..notify].]]
|
||||
]
|
||||
|
||||
[member_heading sched_algorithm_with_properties..new_properties]
|
||||
[member_heading algorithm_with_properties..new_properties]
|
||||
|
||||
virtual fiber_properties * new_properties( context * f);
|
||||
|
||||
[variablelist
|
||||
[[Returns:] [A new instance of [class_link fiber_properties] subclass
|
||||
`PROPS`.]]
|
||||
[[Note:] [By default, `sched_algorithm_with_properties<>::new_properties()`
|
||||
[[Note:] [By default, `algorithm_with_properties<>::new_properties()`
|
||||
simply returns `new PROPS(f)`, placing the `PROPS` instance on the heap.
|
||||
Override this method to allocate `PROPS` some other way. The returned
|
||||
`fiber_properties` pointer must point to the `PROPS` instance to be associated
|
||||
@@ -406,16 +429,19 @@ Of particular note is the fact that `context` contains a hook to participate
|
||||
in a [@http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html
|
||||
`boost::intrusive::list`] typedef'ed as
|
||||
`boost::fibers::scheduler::ready_queue_t`. This hook is reserved for use by
|
||||
[class_link sched_algorithm] implementations. (For instance, [class_link
|
||||
[class_link algorithm] implementations. (For instance, [class_link
|
||||
round_robin] contains a `ready_queue_t` instance to manage its ready fibers.)
|
||||
See [member_link context..ready_is_linked], [member_link context..ready_link],
|
||||
[member_link context..ready_unlink].
|
||||
|
||||
Your `sched_algorithm` implementation may use any container you desire to
|
||||
Your `algorithm` implementation may use any container you desire to
|
||||
manage passed `context` instances. `ready_queue_t` avoids some of the overhead
|
||||
of typical STL containers.
|
||||
|
||||
#include <boost/fiber/context.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
enum class type {
|
||||
none = ``['unspecified]``,
|
||||
@@ -464,6 +490,8 @@ of typical STL containers.
|
||||
|
||||
bool operator<( context const& l, context const& r) noexcept;
|
||||
|
||||
}}
|
||||
|
||||
[static_member_heading context..active]
|
||||
|
||||
static context * active() noexcept;
|
||||
@@ -498,10 +526,10 @@ default-constructed __fiber_id__.]]
|
||||
[[Note:] [`f` must not be the running fiber[s] context. It must not be
|
||||
__blocked__ or terminated. It must not be a `pinned_context`. It must be
|
||||
currently detached. It must not currently be linked into a [class_link
|
||||
sched_algorithm] implementation[s] ready queue. Most of these conditions are
|
||||
implied by `f` being owned by a `sched_algorithm` implementation: that is, it
|
||||
has been passed to [member_link sched_algorithm..awakened] but has not yet
|
||||
been returned by [member_link sched_algorithm..pick_next]. Typically a
|
||||
algorithm] implementation[s] ready queue. Most of these conditions are
|
||||
implied by `f` being owned by a `algorithm` implementation: that is, it
|
||||
has been passed to [member_link algorithm..awakened] but has not yet
|
||||
been returned by [member_link algorithm..pick_next]. Typically a
|
||||
`pick_next()` implementation would call `attach()` with the `context*` it is
|
||||
about to return. It must first remove `f` from its ready queue. You should
|
||||
never pass a `pinned_context` to `attach()` because you should never have
|
||||
@@ -521,13 +549,13 @@ called its `detach()` method in the first place.]]
|
||||
currently associated. `*this` must not be the running fiber[s] context. It
|
||||
must not be __blocked__ or terminated. It must not be a `pinned_context`. It
|
||||
must not be detached already. It must not already be linked into a [class_link
|
||||
sched_algorithm] implementation[s] ready queue. Most of these conditions are
|
||||
implied by `*this` being passed to [member_link sched_algorithm..awakened]; an
|
||||
algorithm] implementation[s] ready queue. Most of these conditions are
|
||||
implied by `*this` being passed to [member_link algorithm..awakened]; an
|
||||
`awakened()` implementation must, however, test for `pinned_context`. It must
|
||||
call `detach()` ['before] linking `*this` into its ready queue.]]
|
||||
[[Note:] [In particular, it is erroneous to attempt to migrate a fiber from
|
||||
one thread to another by calling both `detach()` and `attach()` in the
|
||||
[member_link sched_algorithm..pick_next] method. `pick_next()` is called on
|
||||
[member_link algorithm..pick_next] method. `pick_next()` is called on
|
||||
the intended destination thread. `detach()` must be called on the fiber[s]
|
||||
original thread. You must call `detach()` in the corresponding `awakened()`
|
||||
method.]]
|
||||
@@ -571,7 +599,7 @@ no longer considered a valid context.]]
|
||||
bool ready_is_linked() const noexcept;
|
||||
|
||||
[variablelist
|
||||
[[Returns:] [`true` if `*this` is stored in a [class_link sched_algorithm]
|
||||
[[Returns:] [`true` if `*this` is stored in a [class_link algorithm]
|
||||
implementation's ready-queue.]]
|
||||
[[Throws:] [Nothing]]
|
||||
[[Note:] [Specifically, this method indicates whether [member_link
|
||||
@@ -589,8 +617,8 @@ remote-ready-queue.]]
|
||||
[[Throws:] [Nothing]]
|
||||
[[Note:] [A `context` signaled as ready by another thread is first stored in
|
||||
the fiber manager's remote-ready-queue. This is the mechanism by which the
|
||||
fiber manager protects a [class_link sched_algorithm] implementation from
|
||||
cross-thread [member_link sched_algorithm..awakened] calls.]]
|
||||
fiber manager protects a [class_link algorithm] implementation from
|
||||
cross-thread [member_link algorithm..awakened] calls.]]
|
||||
]
|
||||
|
||||
[member_heading context..wait_is_linked]
|
||||
@@ -699,8 +727,8 @@ with a pointer to `this` at some future time.]]
|
||||
[[Effects:] [Mark the fiber associated with context `*ctx` as being ready to
|
||||
run. This does not immediately resume that fiber; rather it passes the fiber
|
||||
to the scheduler for subsequent resumption. If the scheduler is idle (has not
|
||||
returned from a call to [member_link sched_algorithm..suspend_until]),
|
||||
[member_link sched_algorithm..notify] is called to wake it up.]]
|
||||
returned from a call to [member_link algorithm..suspend_until]),
|
||||
[member_link algorithm..notify] is called to wake it up.]]
|
||||
[[Throws:] [Nothing]]
|
||||
[[Note:] [This is a low-level API potentially useful for integration with
|
||||
other frameworks. It is not intended to be directly invoked by a typical
|
||||
|
||||
@@ -72,6 +72,9 @@ virtual addresses are used.]
|
||||
|
||||
#include <boost/fiber/protected_fixedsize.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
struct protected_fixedsize {
|
||||
protected_fixesize(std::size_t size = traits_type::default_size());
|
||||
|
||||
@@ -80,6 +83,8 @@ virtual addresses are used.]
|
||||
void deallocate( stack_context &);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
[member_heading protected_fixedsize..allocate]
|
||||
|
||||
stack_context allocate();
|
||||
@@ -114,6 +119,9 @@ end of each stack. The memory is managed internally by
|
||||
|
||||
#include <boost/fiber/pooled_fixedsize_stack.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
struct pooled_fixedsize_stack {
|
||||
pooled_fixedsize_stack(std::size_t stack_size = traits_type::default_size(), std::size_t next_size = 32, std::size_t max_size = 0);
|
||||
|
||||
@@ -122,6 +130,8 @@ end of each stack. The memory is managed internally by
|
||||
void deallocate( stack_context &);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
[hding pooled_fixedsize..Constructor]
|
||||
|
||||
pooled_fixedsize_stack(std::size_t stack_size, std::size_t next_size, std::size_t max_size);
|
||||
@@ -160,6 +170,8 @@ address of the stack.]]
|
||||
[[Effects:] [Deallocates the stack space.]]
|
||||
]
|
||||
|
||||
[note This stack allocator is not thread safe.]
|
||||
|
||||
|
||||
[class_heading fixedsize_stack]
|
||||
|
||||
@@ -171,6 +183,9 @@ end of each stack. The memory is simply managed by `std::malloc()` and
|
||||
|
||||
#include <boost/context/fixedsize_stack.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
struct fixedsize_stack {
|
||||
fixedsize_stack(std::size_t size = traits_type::default_size());
|
||||
|
||||
@@ -179,6 +194,8 @@ end of each stack. The memory is simply managed by `std::malloc()` and
|
||||
void deallocate( stack_context &);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
[member_heading fixedsize..allocate]
|
||||
|
||||
stack_context allocate();
|
||||
@@ -220,6 +237,9 @@ command line.]
|
||||
|
||||
#include <boost/fiber/segmented_stack.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
struct segmented_stack {
|
||||
segmented_stack(std::size_t stack_size = traits_type::default_size());
|
||||
|
||||
@@ -228,6 +248,8 @@ command line.]
|
||||
void deallocate( stack_context &);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
[member_heading segmented..allocate]
|
||||
|
||||
stack_context allocate();
|
||||
|
||||
@@ -251,6 +251,7 @@ int main( int argc, char* argv[]) {
|
||||
//]
|
||||
print( tag(), ": io_service returned");
|
||||
print( "Thread ", thread_names.lookup(), ": stopping");
|
||||
std::cout << "done." << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} catch ( std::exception const& e) {
|
||||
print("Exception: ", e.what(), "\n");
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace boost {
|
||||
namespace fibers {
|
||||
namespace asio {
|
||||
|
||||
class round_robin : public sched_algorithm {
|
||||
class round_robin : public algo::algorithm {
|
||||
private:
|
||||
typedef scheduler::ready_queue_t rqueue_t;
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
|
||||
//[priority_scheduler
|
||||
class priority_scheduler :
|
||||
public boost::fibers::sched_algorithm_with_properties< priority_props > {
|
||||
public boost::fibers::algo::algorithm_with_properties< priority_props > {
|
||||
private:
|
||||
typedef boost::fibers::scheduler::ready_queue_t/*< See [link ready_queue_t]. >*/ rqueue_t;
|
||||
|
||||
@@ -87,9 +87,9 @@ public:
|
||||
rqueue_() {
|
||||
}
|
||||
|
||||
// For a subclass of sched_algorithm_with_properties<>, it's important to
|
||||
// For a subclass of algorithm_with_properties<>, it's important to
|
||||
// override the correct awakened() overload.
|
||||
/*<< You must override the [member_link sched_algorithm_with_properties..awakened]
|
||||
/*<< You must override the [member_link algorithm_with_properties..awakened]
|
||||
method. This is how your scheduler receives notification of a
|
||||
fiber that has become ready to run. >>*/
|
||||
virtual void awakened( boost::fibers::context * ctx, priority_props & props) noexcept {
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
//->
|
||||
}
|
||||
|
||||
/*<< You must override the [member_link sched_algorithm_with_properties..pick_next]
|
||||
/*<< You must override the [member_link algorithm_with_properties..pick_next]
|
||||
method. This is how your scheduler actually advises the fiber manager
|
||||
of the next fiber to run. >>*/
|
||||
virtual boost::fibers::context * pick_next() noexcept {
|
||||
@@ -132,13 +132,13 @@ public:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*<< You must override [member_link sched_algorithm_with_properties..has_ready_fibers]
|
||||
/*<< You must override [member_link algorithm_with_properties..has_ready_fibers]
|
||||
to inform the fiber manager of the state of your ready queue. >>*/
|
||||
virtual bool has_ready_fibers() const noexcept {
|
||||
return ! rqueue_.empty();
|
||||
}
|
||||
|
||||
/*<< Overriding [member_link sched_algorithm_with_properties..property_change]
|
||||
/*<< Overriding [member_link algorithm_with_properties..property_change]
|
||||
is optional. This override handles the case in which the running
|
||||
fiber changes the priority of another ready fiber: a fiber already in
|
||||
our queue. In that case, move the updated fiber within the queue. >>*/
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -25,82 +25,6 @@ static std::mutex mtx_count{};
|
||||
static boost::fibers::condition_variable_any cnd_count{};
|
||||
typedef std::unique_lock< std::mutex > lock_t;
|
||||
|
||||
/*****************************************************************************
|
||||
* shared_ready_queue scheduler
|
||||
*****************************************************************************/
|
||||
class shared_ready_queue : public boost::fibers::sched_algorithm {
|
||||
private:
|
||||
typedef std::queue< boost::fibers::context * > rqueue_t;
|
||||
|
||||
static rqueue_t rqueue_;
|
||||
static std::mutex rqueue_mtx_;
|
||||
|
||||
rqueue_t local_queue_{};
|
||||
|
||||
public:
|
||||
//[awakened_ws
|
||||
virtual void awakened( boost::fibers::context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
|
||||
if ( ctx->is_context( boost::fibers::type::pinned_context) ) { /*<
|
||||
recognize when we're passed this thread's main fiber (or an
|
||||
implicit library helper fiber): never put those on the shared
|
||||
queue
|
||||
>*/
|
||||
local_queue_.push( ctx);
|
||||
} else {
|
||||
ctx->detach();
|
||||
lock_t lk(rqueue_mtx_); /*<
|
||||
worker fiber, enqueue on shared queue
|
||||
>*/
|
||||
rqueue_.push( ctx);
|
||||
}
|
||||
}
|
||||
//]
|
||||
//[pick_next_ws
|
||||
virtual boost::fibers::context * pick_next() noexcept {
|
||||
boost::fibers::context * ctx( nullptr);
|
||||
lock_t lk(rqueue_mtx_);
|
||||
if ( ! rqueue_.empty() ) { /*<
|
||||
pop an item from the ready queue
|
||||
>*/
|
||||
ctx = rqueue_.front();
|
||||
rqueue_.pop();
|
||||
lk.unlock();
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
boost::fibers::context::active()->attach( ctx); /*<
|
||||
attach context to current scheduler via the active fiber
|
||||
of this thread
|
||||
>*/
|
||||
} else {
|
||||
lk.unlock();
|
||||
if ( ! local_queue_.empty() ) { /*<
|
||||
nothing in the ready queue, return main or dispatcher fiber
|
||||
>*/
|
||||
ctx = local_queue_.front();
|
||||
local_queue_.pop();
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
//]
|
||||
|
||||
virtual bool has_ready_fibers() const noexcept {
|
||||
lock_t lock(rqueue_mtx_);
|
||||
return ! rqueue_.empty() || ! local_queue_.empty();
|
||||
}
|
||||
|
||||
void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept {
|
||||
// let scheduler (dispatcher-fiber) spin
|
||||
}
|
||||
|
||||
void notify() noexcept {
|
||||
}
|
||||
};
|
||||
|
||||
shared_ready_queue::rqueue_t shared_ready_queue::rqueue_{};
|
||||
std::mutex shared_ready_queue::rqueue_mtx_{};
|
||||
|
||||
/*****************************************************************************
|
||||
* example fiber function
|
||||
*****************************************************************************/
|
||||
@@ -141,8 +65,8 @@ void thread( barrier * b) {
|
||||
std::ostringstream buffer;
|
||||
buffer << "thread started " << std::this_thread::get_id() << std::endl;
|
||||
std::cout << buffer.str() << std::flush;
|
||||
boost::fibers::use_scheduling_algorithm< shared_ready_queue >(); /*<
|
||||
Install the scheduling algorithm `shared_ready_queue` in order to
|
||||
boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); /*<
|
||||
Install the scheduling algorithm `boost::fibers::algo::shared_round_robin` in order to
|
||||
join the work sharing.
|
||||
>*/
|
||||
b->wait(); /*< sync with other threads: allow them to start processing >*/
|
||||
@@ -162,8 +86,8 @@ void thread( barrier * b) {
|
||||
int main( int argc, char *argv[]) {
|
||||
std::cout << "main thread started " << std::this_thread::get_id() << std::endl;
|
||||
//[main_ws
|
||||
boost::fibers::use_scheduling_algorithm< shared_ready_queue >(); /*<
|
||||
Install the scheduling algorithm `shared_ready_queue` in the main thread
|
||||
boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >(); /*<
|
||||
Install the scheduling algorithm `boost::fibers::algo::shared_round_robin` in the main thread
|
||||
too, so each new fiber gets launched into the shared pool.
|
||||
>*/
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class victim_algo : public boost::fibers::sched_algorithm {
|
||||
class victim_algo : public boost::fibers::algo::algorithm {
|
||||
private:
|
||||
typedef work_stealing_queue rqueue_t;
|
||||
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class thief_algo : public boost::fibers::sched_algorithm {
|
||||
class thief_algo : public boost::fibers::algo::algorithm {
|
||||
private:
|
||||
typedef boost::fibers::scheduler::ready_queue_t rqueue_t;
|
||||
typedef work_stealing_queue ws_rqueue_t;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_ALGORITHM_H
|
||||
#define BOOST_FIBERS_ALGORITHM_H
|
||||
#ifndef BOOST_FIBERS_ALGO_ALGORITHM_H
|
||||
#define BOOST_FIBERS_ALGO_ALGORITHM_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <chrono>
|
||||
@@ -24,8 +24,10 @@ namespace fibers {
|
||||
|
||||
class context;
|
||||
|
||||
struct BOOST_FIBERS_DECL sched_algorithm {
|
||||
virtual ~sched_algorithm() {}
|
||||
namespace algo {
|
||||
|
||||
struct BOOST_FIBERS_DECL algorithm {
|
||||
virtual ~algorithm() {}
|
||||
|
||||
virtual void awakened( context *) noexcept = 0;
|
||||
|
||||
@@ -38,7 +40,7 @@ struct BOOST_FIBERS_DECL sched_algorithm {
|
||||
virtual void notify() noexcept = 0;
|
||||
};
|
||||
|
||||
class BOOST_FIBERS_DECL sched_algorithm_with_properties_base : public sched_algorithm {
|
||||
class BOOST_FIBERS_DECL algorithm_with_properties_base : public algorithm {
|
||||
public:
|
||||
// called by fiber_properties::notify() -- don't directly call
|
||||
virtual void property_change_( context * f, fiber_properties * props) noexcept = 0;
|
||||
@@ -49,13 +51,13 @@ protected:
|
||||
};
|
||||
|
||||
template< typename PROPS >
|
||||
struct sched_algorithm_with_properties : public sched_algorithm_with_properties_base {
|
||||
typedef sched_algorithm_with_properties_base super;
|
||||
struct algorithm_with_properties : public algorithm_with_properties_base {
|
||||
typedef algorithm_with_properties_base super;
|
||||
|
||||
// Mark this override 'final': sched_algorithm_with_properties subclasses
|
||||
// Mark this override 'final': algorithm_with_properties subclasses
|
||||
// must override awakened() with properties parameter instead. Otherwise
|
||||
// you'd have to remember to start every subclass awakened() override
|
||||
// with: sched_algorithm_with_properties<PROPS>::awakened(fb);
|
||||
// with: algorithm_with_properties<PROPS>::awakened(fb);
|
||||
virtual void awakened( context * f) noexcept override final {
|
||||
fiber_properties * props = super::get_properties( f);
|
||||
if ( nullptr == props) {
|
||||
@@ -69,10 +71,10 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_
|
||||
"new_properties() must return properties class");
|
||||
super::set_properties( f, props);
|
||||
}
|
||||
// Set sched_algo_ again every time this fiber becomes READY. That
|
||||
// Set algo_ again every time this fiber becomes READY. That
|
||||
// handles the case of a fiber migrating to a new thread with a new
|
||||
// sched_algorithm subclass instance.
|
||||
props->set_sched_algorithm( this);
|
||||
// algorithm subclass instance.
|
||||
props->set_algorithm( this);
|
||||
|
||||
// Okay, now forward the call to subclass override.
|
||||
awakened( f, properties(f) );
|
||||
@@ -90,7 +92,7 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_
|
||||
virtual void property_change( context * f, PROPS & props) noexcept {
|
||||
}
|
||||
|
||||
// implementation for sched_algorithm_with_properties_base method
|
||||
// implementation for algorithm_with_properties_base method
|
||||
void property_change_( context * f, fiber_properties * props ) noexcept override final {
|
||||
property_change( f, * static_cast< PROPS * >( props) );
|
||||
}
|
||||
@@ -103,10 +105,10 @@ struct sched_algorithm_with_properties : public sched_algorithm_with_properties_
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_ALGORITHM_H
|
||||
#endif // BOOST_FIBERS_ALGO_ALGORITHM_H
|
||||
@@ -3,8 +3,8 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H
|
||||
#define BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H
|
||||
#ifndef BOOST_FIBERS_ALGO_ROUND_ROBIN_H
|
||||
#define BOOST_FIBERS_ALGO_ROUND_ROBIN_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/algorithm.hpp>
|
||||
#include <boost/fiber/algo/algorithm.hpp>
|
||||
#include <boost/fiber/context.hpp>
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/scheduler.hpp>
|
||||
@@ -23,12 +23,13 @@
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
class context;
|
||||
|
||||
class BOOST_FIBERS_DECL round_robin : public sched_algorithm {
|
||||
class BOOST_FIBERS_DECL round_robin : public algorithm {
|
||||
private:
|
||||
scheduler::ready_queue_t ready_queue_{};
|
||||
typedef scheduler::ready_queue_t rqueue_t;
|
||||
|
||||
rqueue_t rqueue_{};
|
||||
std::mutex mtx_{};
|
||||
std::condition_variable cnd_{};
|
||||
bool flag_{ false };
|
||||
@@ -50,10 +51,10 @@ public:
|
||||
virtual void notify() noexcept;
|
||||
};
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DEFAULT_ROUND_ROBIN_H
|
||||
#endif // BOOST_FIBERS_ALGO_ROUND_ROBIN_H
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2015.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FIBERS_ALGO_SHARED_ROUND_ROBIN_H
|
||||
#define BOOST_FIBERS_ALGO_SHARED_ROUND_ROBIN_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/algo/algorithm.hpp>
|
||||
#include <boost/fiber/context.hpp>
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/scheduler.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
class BOOST_FIBERS_DECL shared_round_robin : public algorithm {
|
||||
private:
|
||||
typedef std::deque< context * > rqueue_t;
|
||||
typedef scheduler::ready_queue_t lqueue_t;
|
||||
|
||||
static rqueue_t rqueue_;
|
||||
static std::mutex rqueue_mtx_;
|
||||
|
||||
lqueue_t lqueue_{};
|
||||
std::mutex mtx_{};
|
||||
std::condition_variable cnd_{};
|
||||
bool flag_{ false };
|
||||
bool suspend_;
|
||||
|
||||
public:
|
||||
shared_round_robin() = default;
|
||||
|
||||
shared_round_robin( bool suspend) :
|
||||
suspend_{ suspend } {
|
||||
}
|
||||
|
||||
shared_round_robin( shared_round_robin const&) = delete;
|
||||
shared_round_robin( shared_round_robin &&) = delete;
|
||||
|
||||
shared_round_robin & operator=( shared_round_robin const&) = delete;
|
||||
shared_round_robin & operator=( shared_round_robin &&) = delete;
|
||||
|
||||
void awakened( context * ctx) noexcept;
|
||||
|
||||
context * pick_next() noexcept;
|
||||
|
||||
bool has_ready_fibers() const noexcept {
|
||||
std::unique_lock< std::mutex > lock( rqueue_mtx_);
|
||||
return ! rqueue_.empty() || ! lqueue_.empty();
|
||||
}
|
||||
|
||||
void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept;
|
||||
|
||||
void notify() noexcept;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_ALGO_SHARED_ROUND_ROBIN_H
|
||||
@@ -7,7 +7,9 @@
|
||||
#ifndef BOOST_FIBERS_H
|
||||
#define BOOST_FIBERS_H
|
||||
|
||||
#include <boost/fiber/algorithm.hpp>
|
||||
#include <boost/fiber/algo/algorithm.hpp>
|
||||
#include <boost/fiber/algo/round_robin.hpp>
|
||||
#include <boost/fiber/algo/shared_round_robin.hpp>
|
||||
#include <boost/fiber/barrier.hpp>
|
||||
#include <boost/fiber/bounded_channel.hpp>
|
||||
#include <boost/fiber/condition_variable.hpp>
|
||||
|
||||
@@ -52,7 +52,7 @@ PROPS & properties() {
|
||||
fibers::context::active()->get_properties();
|
||||
if ( ! props) {
|
||||
// props could be nullptr if the thread's main fiber has not yet
|
||||
// yielded (not yet passed through sched_algorithm_with_properties::
|
||||
// yielded (not yet passed through algorithm_with_properties::
|
||||
// awakened()). Address that by yielding right now.
|
||||
yield();
|
||||
// Try again to obtain the fiber_properties subclass instance ptr.
|
||||
@@ -60,7 +60,7 @@ PROPS & properties() {
|
||||
// have happened while we were yielding!
|
||||
props = fibers::context::active()->get_properties();
|
||||
// Could still be hosed if the running manager isn't a subclass of
|
||||
// sched_algorithm_with_properties.
|
||||
// algorithm_with_properties.
|
||||
BOOST_ASSERT_MSG(props, "this_fiber::properties not set");
|
||||
}
|
||||
return dynamic_cast< PROPS & >( * props );
|
||||
@@ -78,7 +78,7 @@ bool has_ready_fibers() noexcept {
|
||||
template< typename SchedAlgo, typename ... Args >
|
||||
void use_scheduling_algorithm( Args && ... args) noexcept {
|
||||
boost::fibers::context::active()->get_scheduler()
|
||||
->set_sched_algo(
|
||||
->set_algo(
|
||||
std::unique_ptr< SchedAlgo >(
|
||||
new SchedAlgo( std::forward< Args >( args) ... ) ) );
|
||||
}
|
||||
|
||||
@@ -24,17 +24,22 @@
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
struct sched_algorithm;
|
||||
class context;
|
||||
|
||||
namespace algo {
|
||||
|
||||
struct algorithm;
|
||||
|
||||
}
|
||||
|
||||
class BOOST_FIBERS_DECL fiber_properties {
|
||||
protected:
|
||||
// initialized by constructor
|
||||
context * ctx_;
|
||||
// set every time this fiber becomes READY
|
||||
sched_algorithm * sched_algo_{ nullptr };
|
||||
algo::algorithm * algo_{ nullptr };
|
||||
|
||||
// Inform the relevant sched_algorithm instance that something important
|
||||
// Inform the relevant algorithm instance that something important
|
||||
// has changed, so it can (presumably) adjust its data structures
|
||||
// accordingly.
|
||||
void notify() noexcept;
|
||||
@@ -54,10 +59,10 @@ public:
|
||||
// destroyed via that pointer.
|
||||
virtual ~fiber_properties() = default;
|
||||
|
||||
// not really intended for public use, but sched_algorithm_with_properties
|
||||
// not really intended for public use, but algorithm_with_properties
|
||||
// must be able to call this
|
||||
void set_sched_algorithm( sched_algorithm * algo) noexcept {
|
||||
sched_algo_ = algo;
|
||||
void set_algorithm( algo::algorithm * algo) noexcept {
|
||||
algo_ = algo;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
|
||||
#include <boost/fiber/algorithm.hpp>
|
||||
#include <boost/fiber/algo/algorithm.hpp>
|
||||
#include <boost/fiber/context.hpp>
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/data.hpp>
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
context, detail::worker_hook, & context::worker_hook_ >,
|
||||
intrusive::constant_time_size< false > > worker_queue_t;
|
||||
|
||||
std::unique_ptr< sched_algorithm > sched_algo_;
|
||||
std::unique_ptr< algo::algorithm > algo_;
|
||||
context * main_ctx_{ nullptr };
|
||||
intrusive_ptr< context > dispatcher_ctx_{};
|
||||
// worker-queue contains all context' mananged by this scheduler
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
bool has_ready_fibers() const noexcept;
|
||||
|
||||
void set_sched_algo( std::unique_ptr< sched_algorithm >) noexcept;
|
||||
void set_algo( std::unique_ptr< algo::algorithm >) noexcept;
|
||||
|
||||
void attach_main_context( context *) noexcept;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2015.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -6,14 +7,15 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/fiber/all.hpp>
|
||||
@@ -21,71 +23,16 @@
|
||||
#include "barrier.hpp"
|
||||
#include "bind/bind_processor.hpp"
|
||||
|
||||
using allocator_type = boost::fibers::fixedsize_stack;
|
||||
using channel_type = boost::fibers::unbounded_channel< std::uint64_t >;
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
using duration_type = clock_type::duration;
|
||||
using lock_type = std::unique_lock< std::mutex >;
|
||||
using time_point_type = clock_type::time_point;
|
||||
using channel_type = boost::fibers::unbounded_channel< std::uint64_t >;
|
||||
using allocator_type = boost::fibers::fixedsize_stack;
|
||||
|
||||
static bool done = false;
|
||||
static std::mutex mtx{};
|
||||
static boost::fibers::condition_variable_any cnd{};
|
||||
using lock_t = std::unique_lock< std::mutex >;
|
||||
|
||||
class shared_queue_scheduler : public boost::fibers::sched_algorithm {
|
||||
private:
|
||||
typedef boost::fibers::scheduler::ready_queue_t queue_t;
|
||||
|
||||
static queue_t rqueue_;
|
||||
static std::mutex rqueue_mtx_;
|
||||
|
||||
queue_t lqueue_{};
|
||||
|
||||
public:
|
||||
virtual void awakened( boost::fibers::context * ctx) noexcept {
|
||||
if ( ! ctx->is_context( boost::fibers::type::pinned_context) ) {
|
||||
ctx->detach();
|
||||
lock_t lk( rqueue_mtx_);
|
||||
ctx->ready_link( rqueue_);
|
||||
} else {
|
||||
ctx->ready_link( lqueue_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual boost::fibers::context * pick_next() noexcept {
|
||||
boost::fibers::context * ctx( nullptr);
|
||||
lock_t lk( rqueue_mtx_);
|
||||
if ( ! rqueue_.empty() ) {
|
||||
ctx = & rqueue_.front();
|
||||
rqueue_.pop_front();
|
||||
lk.unlock();
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
boost::fibers::context::active()->attach( ctx);
|
||||
} else {
|
||||
lk.unlock();
|
||||
if ( ! lqueue_.empty() ) {
|
||||
ctx = & lqueue_.front();
|
||||
lqueue_.pop_front();
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
virtual bool has_ready_fibers() const noexcept {
|
||||
lock_t lock( rqueue_mtx_);
|
||||
return ! rqueue_.empty() || ! lqueue_.empty();
|
||||
}
|
||||
|
||||
void suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept {
|
||||
// do not block thread; spin in dispatcher-fiber till ready fibers are available
|
||||
}
|
||||
|
||||
void notify() noexcept {
|
||||
}
|
||||
};
|
||||
|
||||
shared_queue_scheduler::queue_t shared_queue_scheduler::rqueue_{};
|
||||
std::mutex shared_queue_scheduler::rqueue_mtx_{};
|
||||
|
||||
// microbenchmark
|
||||
void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::size_t size, std::size_t div) {
|
||||
@@ -110,26 +57,25 @@ void skynet( allocator_type & salloc, channel_type & c, std::size_t num, std::si
|
||||
|
||||
void thread( unsigned int i, barrier * b) {
|
||||
bind_to_processor( i);
|
||||
boost::fibers::use_scheduling_algorithm< shared_queue_scheduler >();
|
||||
boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >();
|
||||
b->wait();
|
||||
lock_t lk( mtx);
|
||||
lock_type lk( mtx);
|
||||
cnd.wait( lk, [](){ return done; });
|
||||
BOOST_ASSERT( done);
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
boost::fibers::use_scheduling_algorithm< shared_queue_scheduler >();
|
||||
boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_round_robin >();
|
||||
unsigned int n = std::thread::hardware_concurrency();
|
||||
barrier b( n);
|
||||
n -= 1; // this thread
|
||||
bind_to_processor( n);
|
||||
bind_to_processor( n - 1);
|
||||
std::size_t stack_size{ 4048 };
|
||||
std::size_t size{ 100000 };
|
||||
std::size_t div{ 10 };
|
||||
std::vector< std::thread > threads;
|
||||
for ( unsigned int i = 0; i < n; i++) {
|
||||
threads.push_back( std::thread( thread, i, & b) );
|
||||
for ( unsigned int i = 1; i < n; ++i) {
|
||||
threads.push_back( std::thread( thread, i - 1, & b) );
|
||||
};
|
||||
allocator_type salloc{ stack_size };
|
||||
std::uint64_t result{ 0 };
|
||||
@@ -141,7 +87,7 @@ int main() {
|
||||
result = rc.value_pop();
|
||||
duration = clock_type::now() - start;
|
||||
std::cout << "Result: " << result << " in " << duration.count() / 1000000 << " ms" << std::endl;
|
||||
lock_t lk( mtx);
|
||||
lock_type lk( mtx);
|
||||
done = true;
|
||||
lk.unlock();
|
||||
cnd.notify_all();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "boost/fiber/algorithm.hpp"
|
||||
#include "boost/fiber/algo/algorithm.hpp"
|
||||
|
||||
#include "boost/fiber/context.hpp"
|
||||
|
||||
@@ -14,20 +14,21 @@
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
//static
|
||||
fiber_properties *
|
||||
sched_algorithm_with_properties_base::get_properties( context * ctx) noexcept {
|
||||
algorithm_with_properties_base::get_properties( context * ctx) noexcept {
|
||||
return ctx->get_properties();
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
sched_algorithm_with_properties_base::set_properties( context * ctx, fiber_properties * props) noexcept {
|
||||
algorithm_with_properties_base::set_properties( context * ctx, fiber_properties * props) noexcept {
|
||||
ctx->set_properties( props);
|
||||
}
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
@@ -4,7 +4,7 @@
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "boost/fiber/round_robin.hpp"
|
||||
#include "boost/fiber/algo/round_robin.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -14,21 +14,22 @@
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
void
|
||||
round_robin::awakened( context * ctx) noexcept {
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
|
||||
BOOST_ASSERT( ! ctx->ready_is_linked() );
|
||||
ctx->ready_link( ready_queue_);
|
||||
ctx->ready_link( rqueue_);
|
||||
}
|
||||
|
||||
context *
|
||||
round_robin::pick_next() noexcept {
|
||||
context * victim{ nullptr };
|
||||
if ( ! ready_queue_.empty() ) {
|
||||
victim = & ready_queue_.front();
|
||||
ready_queue_.pop_front();
|
||||
if ( ! rqueue_.empty() ) {
|
||||
victim = & rqueue_.front();
|
||||
rqueue_.pop_front();
|
||||
BOOST_ASSERT( nullptr != victim);
|
||||
BOOST_ASSERT( ! victim->ready_is_linked() );
|
||||
}
|
||||
@@ -37,7 +38,7 @@ round_robin::pick_next() noexcept {
|
||||
|
||||
bool
|
||||
round_robin::has_ready_fibers() const noexcept {
|
||||
return ! ready_queue_.empty();
|
||||
return ! rqueue_.empty();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -61,7 +62,7 @@ round_robin::notify() noexcept {
|
||||
cnd_.notify_all();
|
||||
}
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
@@ -0,0 +1,101 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "boost/fiber/algo/shared_round_robin.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "boost/fiber/type.hpp"
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace algo {
|
||||
|
||||
//[awakened_ws
|
||||
void
|
||||
shared_round_robin::awakened( context * ctx) noexcept {
|
||||
if ( ctx->is_context( type::pinned_context) ) { /*<
|
||||
recognize when we're passed this thread's main fiber (or an
|
||||
implicit library helper fiber): never put those on the shared
|
||||
queue
|
||||
>*/
|
||||
lqueue_.push_back( * ctx);
|
||||
} else {
|
||||
ctx->detach();
|
||||
std::unique_lock< std::mutex > lk( rqueue_mtx_); /*<
|
||||
worker fiber, enqueue on shared queue
|
||||
>*/
|
||||
rqueue_.push_back( ctx);
|
||||
}
|
||||
}
|
||||
//]
|
||||
|
||||
//[pick_next_ws
|
||||
context *
|
||||
shared_round_robin::pick_next() noexcept {
|
||||
context * ctx( nullptr);
|
||||
std::unique_lock< std::mutex > lk( rqueue_mtx_);
|
||||
if ( ! rqueue_.empty() ) { /*<
|
||||
pop an item from the ready queue
|
||||
>*/
|
||||
ctx = rqueue_.front();
|
||||
rqueue_.pop_front();
|
||||
lk.unlock();
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
context::active()->attach( ctx); /*<
|
||||
attach context to current scheduler via the active fiber
|
||||
of this thread
|
||||
>*/
|
||||
} else {
|
||||
lk.unlock();
|
||||
if ( ! lqueue_.empty() ) { /*<
|
||||
nothing in the ready queue, return main or dispatcher fiber
|
||||
>*/
|
||||
ctx = & lqueue_.front();
|
||||
lqueue_.pop_front();
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
//]
|
||||
|
||||
void
|
||||
shared_round_robin::suspend_until( std::chrono::steady_clock::time_point const& time_point) noexcept {
|
||||
if ( suspend_) {
|
||||
if ( (std::chrono::steady_clock::time_point::max)() == time_point) {
|
||||
std::unique_lock< std::mutex > lk( mtx_);
|
||||
cnd_.wait( lk, [this](){ return flag_; });
|
||||
flag_ = false;
|
||||
} else {
|
||||
std::unique_lock< std::mutex > lk( mtx_);
|
||||
cnd_.wait_until( lk, time_point, [this](){ return flag_; });
|
||||
flag_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
shared_round_robin::notify() noexcept {
|
||||
if ( suspend_) {
|
||||
std::unique_lock< std::mutex > lk( mtx_);
|
||||
flag_ = true;
|
||||
lk.unlock();
|
||||
cnd_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
shared_round_robin::rqueue_t shared_round_robin::rqueue_{};
|
||||
std::mutex shared_round_robin::rqueue_mtx_{};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "boost/fiber/algorithm.hpp"
|
||||
#include "boost/fiber/algo/algorithm.hpp"
|
||||
#include "boost/fiber/scheduler.hpp"
|
||||
#include "boost/fiber/context.hpp"
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace fibers {
|
||||
|
||||
void
|
||||
fiber_properties::notify() noexcept {
|
||||
BOOST_ASSERT( nullptr != sched_algo_);
|
||||
BOOST_ASSERT( nullptr != algo_);
|
||||
// Application code might change an important property for any fiber at
|
||||
// any time. The fiber in question might be ready, running or waiting.
|
||||
// Significantly, only a fiber which is ready but not actually running is
|
||||
@@ -28,7 +28,7 @@ fiber_properties::notify() noexcept {
|
||||
// with a change to a fiber it's not currently tracking: it will do the
|
||||
// right thing next time the fiber is passed to its awakened() method.
|
||||
if ( ctx_->ready_is_linked() ) {
|
||||
static_cast< sched_algorithm_with_properties_base * >( sched_algo_)->
|
||||
static_cast< algo::algorithm_with_properties_base * >( algo_)->
|
||||
property_change_( ctx_, this);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -11,9 +11,9 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "boost/fiber/algo/round_robin.hpp"
|
||||
#include "boost/fiber/context.hpp"
|
||||
#include "boost/fiber/exceptions.hpp"
|
||||
#include "boost/fiber/round_robin.hpp"
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
@@ -24,7 +24,7 @@ namespace fibers {
|
||||
|
||||
context *
|
||||
scheduler::get_next_() noexcept {
|
||||
context * ctx = sched_algo_->pick_next();
|
||||
context * ctx = algo_->pick_next();
|
||||
//BOOST_ASSERT( nullptr == ctx);
|
||||
//BOOST_ASSERT( this == ctx->get_scheduler() );
|
||||
return ctx;
|
||||
@@ -89,7 +89,7 @@ scheduler::sleep2ready_() noexcept {
|
||||
// reset sleep-tp
|
||||
ctx->tp_ = (std::chrono::steady_clock::time_point::max)();
|
||||
// push new context to ready-queue
|
||||
sched_algo_->awakened( ctx);
|
||||
algo_->awakened( ctx);
|
||||
} else {
|
||||
break; // first context with now < deadline
|
||||
}
|
||||
@@ -97,7 +97,7 @@ scheduler::sleep2ready_() noexcept {
|
||||
}
|
||||
|
||||
scheduler::scheduler() noexcept :
|
||||
sched_algo_{ new round_robin() } {
|
||||
algo_{ new algo::round_robin() } {
|
||||
}
|
||||
|
||||
scheduler::~scheduler() {
|
||||
@@ -135,7 +135,7 @@ scheduler::dispatch() noexcept {
|
||||
bool no_worker = worker_queue_.empty();
|
||||
if ( shutdown_) {
|
||||
// notify sched-algorithm about termination
|
||||
sched_algo_->notify();
|
||||
algo_->notify();
|
||||
if ( no_worker) {
|
||||
break;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ scheduler::dispatch() noexcept {
|
||||
suspend_time = i->tp_;
|
||||
}
|
||||
// no ready context, wait till signaled
|
||||
sched_algo_->suspend_until( suspend_time);
|
||||
algo_->suspend_until( suspend_time);
|
||||
}
|
||||
}
|
||||
// release termianted context'
|
||||
@@ -194,7 +194,7 @@ scheduler::set_ready( context * ctx) noexcept {
|
||||
// for safety unlink it from ready-queue
|
||||
ctx->ready_unlink();
|
||||
// push new context to ready-queue
|
||||
sched_algo_->awakened( ctx);
|
||||
algo_->awakened( ctx);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -214,7 +214,7 @@ scheduler::set_remote_ready( context * ctx) noexcept {
|
||||
remote_ready_queue_.push_back( ctx);
|
||||
lk.unlock();
|
||||
// notify scheduler
|
||||
sched_algo_->notify();
|
||||
algo_->notify();
|
||||
}
|
||||
|
||||
#if (BOOST_EXECUTION_CONTEXT==1)
|
||||
@@ -337,16 +337,16 @@ scheduler::suspend( detail::spinlock_lock & lk) noexcept {
|
||||
|
||||
bool
|
||||
scheduler::has_ready_fibers() const noexcept {
|
||||
return sched_algo_->has_ready_fibers();
|
||||
return algo_->has_ready_fibers();
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::set_sched_algo( std::unique_ptr< sched_algorithm > algo) noexcept {
|
||||
scheduler::set_algo( std::unique_ptr< algo::algorithm > algo) noexcept {
|
||||
// move remaining cotnext in current scheduler to new one
|
||||
while ( sched_algo_->has_ready_fibers() ) {
|
||||
algo->awakened( sched_algo_->pick_next() );
|
||||
while ( algo_->has_ready_fibers() ) {
|
||||
algo->awakened( algo_->pick_next() );
|
||||
}
|
||||
sched_algo_ = std::move( algo);
|
||||
algo_ = std::move( algo);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -375,7 +375,7 @@ scheduler::attach_dispatcher_context( intrusive_ptr< context > dispatcher_ctx) n
|
||||
// the dispatcher-context is resumed and
|
||||
// scheduler::dispatch() is executed
|
||||
dispatcher_ctx_->scheduler_ = this;
|
||||
sched_algo_->awakened( dispatcher_ctx_.get() );
|
||||
algo_->awakened( dispatcher_ctx_.get() );
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user