diff --git a/doc/fiber.qbk b/doc/fiber.qbk index 381dc8a5..7cc1d092 100644 --- a/doc/fiber.qbk +++ b/doc/fiber.qbk @@ -20,12 +20,11 @@ bool operator<( fiber const& l, fiber const& r) noexcept; void swap( fiber & l, fiber & r) noexcept; - class fiber_group; class attributes; - struct algorithm; + struct sched_algorithm; class round_robin; - void set_scheduling_algorithm( algorithm * al) + void set_scheduling_algorithm( sched_algorithm * al) } @@ -33,9 +32,12 @@ fibers::id get_id() noexcept; void yield(); - void sleep_until( fibers::clock_type::time_point const& timeout_point); + template< typename TimePoint > + void sleep_until( TimePoint const& timeout_point); template< typename Rep, typename Period > - void sleep_for( fibers::clock_type::duration< Rep, Period > const& timeout_duration); + void sleep_for( chrono::duration< Rep, Period > const& timeout_duration); + bool thread_affinity() noexcept; + void thread_affinity( bool) noexcept; void interruption_point(); bool interruption_requested() noexcept; @@ -210,21 +212,42 @@ operators on __fiber_id__ yield a total order for every non-equal __fiber_id__. fiber() noexcept; template< typename Fn > - explicit fiber( Fn fn, attributes const& attr = attributes(), - stack_allocator const& stack_alloc = stack_allocator(), - std::allocator< fiber > const& alloc = - std::allocator< fiber >() ); + explicit fiber( Fn fn); - template< typename Fn, typename StackAllocator > - explicit fiber( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - std::allocator< fiber > const& alloc = - std::allocator< fiber >() ); + template< typename Fn > + fiber( attributes const& attrs, Fn fn); - template< typename Fn, typename StackAllocator, typename Allocator > - explicit fiber( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - Allocator const& alloc); + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn fn); + + template< typename Fn > + explicit fiber( Fn && fn); + + template< typename Fn > + fiber( attributes const& attrs, Fn && fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn && fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn && fn); + + #ifdef BOOST_FIBERS_USE_VARIADRIC_FIBER + template< typename Fn, class .. Args > + explicit fiber( Fn && fn, Args && ... args); + + template< typename Fn, class .. Args > + fiber( attributes const& attrs, Fn && fn, Args && ... args); + + template< typename StackAllocator, typename Fn, class .. Args > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn && fn, Args && ... args); + + template< typename StackAllocator, typename Fn, class .. Args > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn && fn, Args && ... args); + #endif ~fiber(); @@ -236,7 +259,7 @@ operators on __fiber_id__ yield a total order for every non-equal __fiber_id__. fiber & operator=( fiber && other) noexcept; - operator safe_bool() const noexcept; + operator bool() const noexcept; bool operator!() const noexcept; @@ -277,21 +300,42 @@ operators on __fiber_id__ yield a total order for every non-equal __fiber_id__. [heading Constructor] template< typename Fn > - explicit fiber( Fn fn, attributes const& attr = attributes(), - stack_allocator const& stack_alloc = stack_allocator(), - std::allocator< fiber > const& alloc = - std::allocator< fiber >() ); + explicit fiber( Fn fn); - template< typename Fn, typename StackAllocator > - explicit fiber( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - std::allocator< fiber > const& alloc = - std::allocator< fiber >() ); + template< typename Fn > + fiber( attributes const& attrs, Fn fn); - template< typename Fn, typename StackAllocator, typename Allocator > - explicit fiber( Fn fn, attributes const& attr, - StackAllocator const& stack_alloc, - Allocator const& alloc); + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn fn); + + template< typename Fn > + explicit fiber( Fn && fn); + + template< typename Fn > + fiber( attributes const& attrs, Fn && fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn && fn); + + template< typename StackAllocator, typename Fn > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn && fn); + + #ifdef BOOST_FIBERS_USE_VARIADRIC_FIBER + template< typename Fn, class .. Args > + explicit fiber( Fn && fn, Args && ... args); + + template< typename Fn, class .. Args > + fiber( attributes const& attrs, Fn && fn, Args && ... args); + + template< typename StackAllocator, typename Fn, class .. Args > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, Fn && fn, Args && ... args); + + template< typename StackAllocator, typename Fn, class .. Args > + fiber( allocator_arg_t, StackAllocator const& stack_alloc, attributes const& attrs, Fn && fn, Args && ... args); + #endif [variablelist [[Preconditions:] [`Fn` must be copyable or movable.]] @@ -460,9 +504,9 @@ an applicable scheduler, a fiber is allowed to migrate across threads.]] [[See also:] [[ns_function_link this_fiber..thread_affinity]]] ] -[member_heading fiber..operator safe_bool] +[member_heading fiber..operator bool] - operator safe_bool() const noexcept; + operator bool() const noexcept; [variablelist [[Returns:] [`true` if `*this` refers to a fiber of execution which has not @@ -507,7 +551,7 @@ prior to the call.]] [function_heading set_scheduling_algorithm] - void set_scheduling_algorithm( algorithm* scheduler ); + void set_scheduling_algorithm( sched_algorithm* scheduler ); [variablelist [[Effects:] [Directs __boost_fiber__ to use `scheduler`, which must be a @@ -532,181 +576,6 @@ ensure that the instance is destroyed on thread termination.)]] [endsect] [/ section Class fiber] -[#class_fiber_group] -[section:fiber_group Class `fiber_group`] - -__fiber_group__ represents a collection of fibers which can be collectively -waited on or interrupted. -__fiber_group__ is neither copyable nor movable. - - #include - - class fiber_group - { - public: - fiber_group() {} - - ~fiber_group(); - - fiber_group( fiber_group const& other) = delete; - - fiber_group & operator=( fiber_group const& other) = delete; - - bool is_this_fiber_in(); - - bool is_fiber_in( fiber * f); - - template< typename Fn > - fiber * create_fiber( Fn fn, attributes attrs = attributes() ); - - template< typename Fn, typename StackAllocator > - fiber * create_fiber( Fn fn, attributes attrs, - StackAllocator const& stack_alloc); - - template< typename Fn, typename StackAllocator, typename Allocator > - fiber * create_fiber( Fn fn, attributes attrs, - StackAllocator const& stack_alloc, - Allocator const& alloc); - - void add_fiber( fiber * f); - - void remove_fiber( fiber * f); - - void join_all(); - - void interrupt_all(); - - std::size_t size() const; - }; - -[heading Constructor] - - fiber_group(); - -[variablelist -[[Effects:] [Create a new fiber group with no fibers.]] -] - -[heading Destructor] - - ~fiber_group(); - -[variablelist -[[Effects:] [Destroy `*this` and all __fiber__ objects in the group.]] -] - -[member_heading fiber_group..create_fiber] - - template< typename Fn > - fiber * create_fiber( Fn fn, attributes attrs = attributes() ); - - template< typename Fn, typename StackAllocator > - fiber * create_fiber( Fn fn, attributes attrs, - StackAllocator const& stack_alloc); - - template< typename Fn, typename StackAllocator, typename Allocator > - fiber * create_fiber( Fn fn, attributes attrs, - StackAllocator const& stack_alloc, - Allocator const& alloc); - -[variablelist -[[Effects:] [Create a new __fiber__ object as-if by `new fiber( fn)` and add it -to the group.]] -[[Postcondition:] [`this->size()` is increased by one, the new fiber is running.]] -[[Returns:] [A pointer to the new __fiber__ object.]] -] - -[member_heading fiber_group..add_fiber] - - void add_fiber( fiber * f); - -[variablelist -[[Precondition:] [The expression `delete f` is well-formed and will not result -in undefined behaviour and `is_fiber_in(f) == false`.]] -[[Effects:] [Add __fiber__ object pointed to by `f` to the group.]] -[[Postcondition:] [`this->size()` is increased by one.]] -[[Note:] [Unless the same `f` is later passed to `remove_fiber()`, `*this` -becomes responsible for the lifespan of `*f`. When the `fiber_group` is -destroyed, `*f` will also be destroyed.]] -] - -The Precondition implies that `f` must point to a heap __fiber__ object. This -is erroneous: - - boost::fibers::fiber_group fg; - { - boost::fibers::fiber f(somefunc); - fg.add_fiber(&f); - } // WRONG! - -Instead, use the following: - - boost::fibers::fiber_group fg; - { - boost::fibers::fiber* f = new boost::fibers::fiber(somefunc); - fg.add_fiber(f); - } // okay, fg is now responsible for *f - -[member_heading fiber_group..remove_fiber] - - void remove_fiber( fiber * f); - -[variablelist -[[Effects:] [If `f` is a member of the group, remove it without calling -`delete`.]] -[[Postcondition:] [If `f` was a member of the group, `this->size()` is -decreased by one.]] -] - -[member_heading fiber_group..join_all] - - void join_all(); - -[variablelist -[[Requires:] [`is_this_fiber_in() == false`.]] -[[Effects:] [Call `join()` on each __fiber__ object in the group.]] -[[Postcondition:] [Every fiber in the group has terminated.]] -[[Note:] [Since __join__ is one of the predefined __interruption_points__, -`join_all()` is also an interruption point.]] -] - -[member_heading fiber_group..is_this_fiber_in] - - bool is_this_fiber_in(); - -[variablelist -[[Returns:] [true if there is a fiber `f` in the group such that -`f.get_id() == this_fiber::get_id()`.]] -] - -[member_heading fiber_group..is_fiber_in] - - bool is_fiber_in( fiber * f); - -[variablelist -[[Returns:] [true if there is a fiber `fx` in the group such that -`fx.get_id() == f->get_id()`.]] -] - -[member_heading fiber_group..interrupt_all] - - void interrupt_all(); - -[variablelist -[[Effects:] [Call `interrupt()` on each __fiber__ object in the group.]] -] - -[member_heading fiber_group..size] - - int size(); - -[variablelist -[[Returns:] [The number of fibers in the group.]] -[[Throws:] [Nothing.]] -] - - -[endsect] [/ section Class fiber_group] [#class_attributes] [section:attributes Class attributes] diff --git a/doc/scheduling.qbk b/doc/scheduling.qbk index b124e00f..824d4978 100644 --- a/doc/scheduling.qbk +++ b/doc/scheduling.qbk @@ -34,169 +34,42 @@ it to [function_link set_scheduling_algorithm]. #include - struct algorithm + struct sched_algorithm { - virtual ~algorithm() {} + virtual ~sched_algorithm() {} - algorithm( algorithm const&) = delete; - algorithm & operator=( algorithm const&) = delete; + virtual void awakened( detail::worker_fiber *) = 0; - virtual void spawn( detail::worker_fiber::ptr_t const&) = 0; + virtual detail::worker_fiber * pick_next() = 0; - virtual void priority( detail::worker_fiber::ptr_t const&, int) noexcept = 0; - - virtual void join( detail::worker_fiber::ptr_t const&) = 0; - - virtual detail::worker_fiber::ptr_t active() noexcept = 0; - - virtual bool run() = 0; - - virtual void wait( unique_lock< detail::spinlock > &) = 0; - virtual bool wait_until( clock_type::time_point const&, - unique_lock< detail::spinlock > &) = 0; - template< typename Rep, typename Period > - bool wait_for( chrono::duration< Rep, Period > const&, - unique_lock< detail::spinlock > &); - - virtual void yield() = 0; - - virtual detail::worker_fiber::id get_main_id() = 0; - virtual detail::fiber_base::ptr_t get_main_fiber() = 0; + virtual void priority( detail::worker_fiber *, int) noexcept = 0; }; - void set_scheduling_algorithm( algorithm *); + void set_scheduling_algorithm( sched_algorithm *); -[member_heading algorithm..spawn] +[member_heading algorithm..awakened] - virtual void spawn( detail::worker_fiber::ptr_t const& f) = 0; + virtual void awakened( detail::worker_fiber * f) = 0; [variablelist -[[Effects:] [Spawns fiber `f`, e.g. `f` will be entered the first time -or resumed where it was suspended before. Suspends the current fiber.]] +[[Effects:] [Marks fiber `f`, to be ready to run.]] +] + +[member_heading algorithm..pick_next] + + virtual detail::worker_fiber * pick_next() = 0; + +[variablelist +[[Effects:] [Depending on the scheduling algorithm, this function returns the +fiber which has to be resumed next.]] ] [member_heading algorithm..priority] - virtual void priority( detail::worker_fiber::ptr_t const& f, int p) noexcept = 0; + virtual void priority( detail::worker_fiber *, int) noexcept = 0; [variablelist -[[Effects:] [Sets priority `p` for fiber `f`. Interpretation of "priority" -is entirely up to the subclass.]] -[[Throws:] [Nothing]] -] - -[member_heading algorithm..join] - - virtual void join( detail::worker_fiber::ptr_t const& f) = 0; - -[variablelist -[[Effects:] [Suspends the current fiber until fiber `f` terminates.]] -] - -[member_heading algorithm..active] - - virtual detail::worker_fiber::ptr_t active() noexcept = 0; - -[variablelist -[[Returns:] [The active fiber, or a null-pointer if the current -execution context is not a fiber managed by this __algo__ instance.]] -[[Note:] [While the initial context for a given thread is conceptually also a -fiber, it has no associated `detail::worker_fiber` instance. This is when -`active()` returns null. Higher-level __boost_fiber__ operations treat a -thread's initial context as equivalent to an explicitly-launched fiber, but -this method operates below that level of abstraction.]] -[[See also:] [[member_link algorithm..get_main_id]]] -] - -[member_heading algorithm..run] - - virtual bool run() = 0; - -[variablelist -[[Effects:] [Selects one fiber in ready state and runs it until it suspends. -The choice of fiber is up to the subclass instance.]] -[[Returns:] [Returns `true` if one fiber was ready and successfully executed, `false` -otherwise.]] -] - -[member_heading algorithm..wait] - - virtual void wait( unique_lock< detail::spinlock > & lk) = 0; - -[variablelist -[[Precondition:] [`lk` is locked by the current fiber. It locks the spinlock -protecting the internal state of a mutex or condition_variable.]] -[[Effects:] [Current fiber is set to waiting-state and gets suspended.]] -[[Postcondition:] [`lk` is unlocked.]] -] - -[member_heading algorithm..wait_until] - - virtual bool wait_until( clock_type::time_point const& timeout_time, - unique_lock< detail::spinlock > & lk) = 0; - -[variablelist -[[Precondition:] [`lk` is locked by the current fiber. It locks the spinlock -protecting the internal state of a mutex or condition_variable.]] -[[Effects:] [Current fiber is set to waiting-state and gets suspended.]] -[[Returns:] [Returns `true` if fiber was resumed before time-point -`timeout_time` was reached, `false` otherwise.]] -[[Postcondition:] [`lk` is unlocked.]] -] - -[member_heading algorithm..wait_for] - - template< typename Rep, typename Period > - bool wait_for( chrono::duration< Rep, Period > const& timeout_duration, - unique_lock< detail::spinlock > & lk) - -[variablelist -[[Precondition:] [`lk` is locked by the current fiber. It locks the spinlock -protecting the internal state of a mutex or condition_variable.]] -[[Effects:] [Current fiber is set to waiting-state and gets suspended.]] -[[Returns:] [Returns `true` if fiber was resumed before time-duration -`timeout_duration` has passed, `false` otherwise.]] -[[Postcondition:] [`lk` is unlocked.]] -] - -[member_heading algorithm..yield] - - virtual void yield() = 0; - -[variablelist -[[Effects:] [Suspends active fiber without waiting; that is, the current fiber -is immediately set to ready-state.]] -] - -[member_heading algorithm..get_main_id] - - virtual detail::worker_fiber::id get_main_id() = 0; - -[variablelist -[[Returns:] [A `worker_fiber::id` associated with the initial context of the -thread on which the scheduler is running.]] -[[Note:] [While the initial context for a given thread is conceptually also a -fiber, it has no associated `detail::worker_fiber` instance. Higher-level -__boost_fiber__ operations treat a thread's initial context as equivalent to -an explicitly-launched fiber, but this method operates below that level of -abstraction.]] -[[See also:] [[member_link algorithm..active]]] -] - -[member_heading algorithm..get_main_fiber] - - virtual detail::fiber_base::ptr_t get_main_fiber() = 0; - -[variablelist -[[Returns:] [A `fiber_base::ptr_t` associated with the initial context of the -thread on which the scheduler is running.]] -[[Note:] [While the initial context for a given thread is conceptually also a -fiber, it has no associated `detail::worker_fiber` instance. Higher-level -__boost_fiber__ operations treat a thread's initial context as equivalent to -an explicitly-launched fiber, but this method operates below that level of -abstraction. The `fiber_base::ptr_t` is used in condition_variable and mutex -to signal threads initial context.]] -[[See also:] [[member_link algorithm..active]]] +[[Effects:] [Reschedule the fiber depending on the priority.]] ] @@ -204,28 +77,8 @@ to signal threads initial context.]] This class implements __algo__ and schedules fibers in round-robin fashion. -[class_heading round_robin_ws] - -`round_robin_ws` is intended to be used for migrating fibers between threads (different -schedulers). For this purpose the class has two additional functions - `steal_from()` and -`migrate_to()`. -This functionality can be used to implement work-stealing/-sharing in a threadpool. - - boost::fibers::round_robin_ws rr; - boost::fibers::set_scheduling_algorithm( & rr); - - // steal a fiber from a scheduler `other_rr` running in another thread - boost::fibers::fiber f( other_rr->steal_from() ); - - // check if stealing was successful - if ( f) - { - // migrate stolen fiber to scheduler running in this thread - rr.migrate_to( f); - - // detach fiber - f.detach(); - } +[info The exsample section provides an scheduler used for migrating fibers +(work-stealing) between threads (different schedulers).] [endsect]