mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-19 02:12:24 +00:00
965 lines
29 KiB
Plaintext
965 lines
29 KiB
Plaintext
[/
|
|
(C) Copyright 2007-8 Anthony Williams.
|
|
(C) Copyright 2011-12 Vicente J. Botet Escriba.
|
|
(C) Copyright 2013 Oliver Kowalke.
|
|
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).
|
|
]
|
|
|
|
[section:fiber_mgmt Fiber management]
|
|
|
|
[heading Synopsis]
|
|
|
|
#include <boost/fiber/all.hpp>
|
|
|
|
namespace boost {
|
|
namespace fibers {
|
|
|
|
class fiber;
|
|
bool operator<( fiber const& l, fiber const& r) noexcept;
|
|
void swap( fiber & l, fiber & r) noexcept;
|
|
|
|
class fiber_group;
|
|
class attributes;
|
|
|
|
struct algorithm;
|
|
class round_robin;
|
|
void set_scheduling_algorithm( algorithm * al)
|
|
|
|
}
|
|
|
|
namespace this_fiber {
|
|
|
|
fibers::id get_id() noexcept;
|
|
void yield();
|
|
void sleep_until( fibers::clock_type::time_point const& timeout_point);
|
|
template< typename Rep, typename Period >
|
|
void sleep_for( fibers::clock_type::duration< Rep, Period > const& timeout_duration);
|
|
|
|
void interruption_point();
|
|
bool interruption_requested() noexcept;
|
|
bool interruption_enabled() noexcept;
|
|
class disable_interruption;
|
|
class restore_interruption;
|
|
|
|
}}
|
|
|
|
|
|
[heading Tutorial]
|
|
|
|
Each __fiber__ represents a micro-thread which will be launched and managed
|
|
cooperatively by a scheduler. Objects of type __fiber__ are only moveable.
|
|
|
|
boost::fibers::fiber f1; // not-a-fiber
|
|
|
|
void f()
|
|
{
|
|
boost::fibers::fiber f2( some_fn);
|
|
|
|
f1 = boost::move( f2); // f2 moved to f1
|
|
}
|
|
|
|
|
|
[heading Launching]
|
|
|
|
A new fiber is launched by passing an object of a callable type that can be
|
|
invoked with no parameters.
|
|
If the object must not (or cannot) be copied, then ['boost::ref] can be used to
|
|
pass in a reference to the function object. In this case, the user must ensure
|
|
that the referenced object outlives the newly-created fiber.
|
|
|
|
struct callable
|
|
{ void operator()(); };
|
|
|
|
boost::fibers::fiber copies_are_safe()
|
|
{
|
|
callable x;
|
|
return boost::fibers::fiber( x);
|
|
} // x is destroyed, but the newly-created fiber has a copy, so this is OK
|
|
|
|
boost::fibers::fiber oops()
|
|
{
|
|
callable x;
|
|
return boost::fibers::fiber( boost::ref( x) );
|
|
} // x is destroyed, but the newly-created fiber still has a reference
|
|
// this leads to undefined behaviour
|
|
|
|
Control is immediately transferred to the spawned __fiber__ at
|
|
construction. When the constructor returns, the __fiber__ might be complete or
|
|
might have suspended.
|
|
|
|
|
|
[heading Exceptions]
|
|
|
|
Exceptions thrown by the function or callable object passed to the __fiber__
|
|
constructor are consumed by the framework. If you need to know which
|
|
exception was thrown, use __future__ and __packaged_task__.
|
|
|
|
|
|
[heading Detaching]
|
|
|
|
A __fiber__ can be detached by explicitly invoking the __detach__ member
|
|
function. After __detach__ is called on a fiber object, that object represents
|
|
__not_a_fiber__. The fiber object may then safely be destroyed.
|
|
|
|
boost::fibers::fiber( some_fn).detach();
|
|
|
|
|
|
[heading Joining]
|
|
|
|
In order to wait for a fiber to finish, the __join__ member function of the
|
|
__fiber__ object can be used. __join__ will block until the __fiber__ object
|
|
has completed.
|
|
If the __fiber__ has already completed, or the __fiber__ object represents
|
|
__not_a_fiber__, then __join__ returns immediately.
|
|
|
|
void some_fn()
|
|
{ ... }
|
|
|
|
boost::fibers::fiber f( some_fn);
|
|
...
|
|
f.join();
|
|
|
|
If the fiber has already completed, then __join__ returns immediately and
|
|
the joined __fiber__ object becomes __not_a_fiber__.
|
|
|
|
|
|
[heading Destruction]
|
|
|
|
When a __fiber__ object representing a valid execution context is destroyed, the
|
|
program terminates if the fiber is __joinable__. If you intend the
|
|
fiber to outlive the __fiber__ object that launched it, use the __detach__
|
|
method.
|
|
|
|
{
|
|
boost::fibers::fiber f( some_fn);
|
|
} // std::terminate() will be called
|
|
|
|
{
|
|
boost::fibers::fiber f(some_fn);
|
|
f.detach();
|
|
} // okay, program continues
|
|
|
|
|
|
[#interruption]
|
|
[heading Interruption]
|
|
|
|
A valid fiber can be interrupted by invoking its __interrupt__ member function.
|
|
The next time that fiber executes one of the specific __interruption_points__ with
|
|
interruption enabled, a __fiber_interrupted__ exception will be thrown.
|
|
If this exception is not caught, the fiber will be terminated, its stack unwound,
|
|
its stack objects properly destroyed.
|
|
|
|
With __disable_interruption__ a fiber can avoid being interrupted.
|
|
|
|
// interruption enabled at this point
|
|
{
|
|
boost::this_fiber::disable_interruption di1;
|
|
// interruption disabled
|
|
{
|
|
boost::this::fiber::disable_interruption di2;
|
|
// interruption still disabled
|
|
} // di2 destroyed; interruption state restored
|
|
// interruption still disabled
|
|
} // di destroyed; interruption state restored
|
|
// interruption enabled
|
|
|
|
At any point, the interruption state for the current thread can be queried by
|
|
calling __interruption_enabled__.
|
|
The following __interruption_points__ are defined and will throw
|
|
__fiber_interrupted__ if __interruption_requested__ and
|
|
__interruption_enabled__.
|
|
|
|
* __join__
|
|
* __barrier_wait__
|
|
* __cond_wait__
|
|
* __cond_wait_for__
|
|
* __cond_wait_until__
|
|
* __sleep_for__
|
|
* __sleep_until__
|
|
* __interruption_point__
|
|
|
|
[#class_fiber_id]
|
|
[heading Fiber IDs]
|
|
|
|
Objects of class __fiber_id__ can be used to identify fibers. Each running
|
|
__fiber__ has a unique __fiber_id__ obtainable from the corresponding __fiber__
|
|
by calling the __get_id__ member function.
|
|
Objects of class __fiber_id__ can be copied, and used as keys in associative
|
|
containers: the full range of comparison operators is provided.
|
|
They can also be written to an output stream using the stream insertion
|
|
operator, though the output format is unspecified.
|
|
|
|
Each instance of __fiber_id__ either refers to some fiber, or __not_a_fiber__.
|
|
Instances that refer to __not_a_fiber__ compare equal to each other, but
|
|
not equal to any instances that refer to an actual fiber. The comparison
|
|
operators on __fiber_id__ yield a total order for every non-equal __fiber_id__.
|
|
|
|
|
|
[#class_fiber]
|
|
[section:fiber Class `fiber`]
|
|
|
|
#include <boost/fiber/fiber.hpp>
|
|
|
|
class fiber
|
|
{
|
|
public:
|
|
typedef uspecified-class 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 >() );
|
|
|
|
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, typename StackAllocator, typename Allocator >
|
|
explicit fiber( Fn fn, attributes const& attr,
|
|
StackAllocator const& stack_alloc,
|
|
Allocator const& alloc);
|
|
|
|
~fiber();
|
|
|
|
fiber( fiber const& other) = delete;
|
|
|
|
fiber & operator=( fiber const& other) = delete;
|
|
|
|
fiber( fiber && other) noexcept;
|
|
|
|
fiber & operator=( fiber && other) noexcept;
|
|
|
|
operator safe_bool() const noexcept;
|
|
|
|
bool operator!() const noexcept;
|
|
|
|
void swap( fiber & other) noexcept;
|
|
|
|
bool joinable() const noexcept;
|
|
|
|
id get_id() const noexcept;
|
|
|
|
int priority() const noexcept;
|
|
void priority( int) noexcept;
|
|
|
|
bool thread_affinity() const noexcept;
|
|
void thread_affinity( bool) noexcept;
|
|
|
|
void detach() noexcept;
|
|
|
|
void join();
|
|
|
|
void interrupt() noexcept;
|
|
};
|
|
|
|
bool operator<( fiber const& l, fiber const& r) noexcept;
|
|
|
|
void swap( fiber & l, fiber & r) noexcept;
|
|
|
|
|
|
[heading Default constructor]
|
|
|
|
fiber() noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Constructs a __fiber__ instance that refers to __not_a_fiber__.]]
|
|
[[Postconditions:] [`this->get_id() == fiber::id()`]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[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 >() );
|
|
|
|
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, typename StackAllocator, typename Allocator >
|
|
explicit fiber( Fn fn, attributes const& attr,
|
|
StackAllocator const& stack_alloc,
|
|
Allocator const& alloc);
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`Fn` must be copyable or movable.]]
|
|
[[Effects:] [`fn` is copied into internal storage for access by the new fiber.]]
|
|
[[Postconditions:] [`*this` refers to the newly created fiber of execution.]]
|
|
[[Throws:] [__fiber_exception__ if an error occurs.]]
|
|
[[Note:] [StackAllocator is required to allocate a stack for the internal
|
|
coroutine.]]
|
|
]
|
|
|
|
[heading Move constructor]
|
|
|
|
fiber( fiber && other) noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Transfers ownership of the fiber managed by `other` to the newly
|
|
constructed __fiber__ instance.]]
|
|
[[Postconditions:] [`other.get_id() == fiber::id()` and `get_id()` returns the
|
|
value of `other.get_id()` prior to the construction]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[heading Move assignment operator]
|
|
|
|
fiber & operator=( fiber && other) noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Transfers ownership of the fiber managed by `other` (if any) to
|
|
`*this`.]]
|
|
[[Postconditions:] [`other->get_id() == fiber::id()` and `get_id()` returns the
|
|
value of `other.get_id()` prior to the assignment.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[heading Destructor]
|
|
|
|
~fiber();
|
|
|
|
[variablelist
|
|
[[Effects:] [If the fiber is __joinable__, calls std::terminate. Destroys
|
|
`*this`.]]
|
|
[[Throws:] [Nothing.]]
|
|
[[Note:] [The programmer must ensure that the destructor is never executed while
|
|
the fiber is still __joinable__. Even if you know (by calling
|
|
[member_link fiber..operator safe_bool]) that the fiber has completed, you must
|
|
still call either __join__ or __detach__ before destroying the `fiber` object.]]
|
|
]
|
|
|
|
[member_heading fiber..joinable]
|
|
|
|
bool joinable() const noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this` refers to a fiber of execution, which may or
|
|
may not have completed; otherwise `false`.]]
|
|
[[Throws:] [Nothing]]
|
|
[[See also:] [[member_link fiber..operator safe_bool]]]
|
|
]
|
|
|
|
[member_heading fiber..join]
|
|
|
|
void join();
|
|
|
|
[variablelist
|
|
[[Preconditions:] [the fiber is __joinable__.]]
|
|
[[Effects:] [If `*this` refers to a fiber of execution, waits for that fiber to
|
|
complete.]]
|
|
[[Postconditions:] [If `*this` refers to a fiber of execution on entry, that
|
|
fiber has completed. `*this` no longer refers to any fiber of execution.]]
|
|
[[Throws:] [__fiber_interrupted__ if the current fiber is interrupted or
|
|
`system_error`]]
|
|
[[Error Conditions:] [
|
|
[*resource_deadlock_would_occur]: if `this->get_id() == boost::this_fiber::get_id()`.
|
|
[*invalid_argument]: if the fiber is not __joinable__.]]
|
|
[[Notes:] [`join()` is one of the predefined __interruption_points__.]]
|
|
]
|
|
|
|
[member_heading fiber..detach]
|
|
|
|
void detach();
|
|
|
|
[variablelist
|
|
[[Preconditions:] [the fiber is __joinable__.]]
|
|
[[Effects:] [The fiber of execution becomes detached, and no longer has an
|
|
associated __fiber__ object.]]
|
|
[[Postconditions:] [`*this` no longer refers to any fiber of execution.]]
|
|
[[Throws:] [`system_error`]]
|
|
[[Error Conditions:] [
|
|
[*invalid_argument]: if the fiber is not __joinable__.]]
|
|
]
|
|
|
|
[member_heading fiber..get_id]
|
|
|
|
fiber::id get_id() const noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to a fiber of execution, an instance of
|
|
__fiber_id__ that represents that fiber. Otherwise returns a
|
|
default-constructed __fiber_id__.]]
|
|
[[Throws:] [Nothing]]
|
|
[[See also:] [[ns_function_link this_fiber..get_id]]]
|
|
]
|
|
|
|
[member_heading fiber..interrupt]
|
|
|
|
void interrupt();
|
|
|
|
[variablelist
|
|
[[Effects:] [If `*this` refers to a fiber of execution, request that the fiber
|
|
will be interrupted the next time it enters one of the predefined
|
|
__interruption_points__ with interruption enabled, or if it is currently
|
|
__blocked__ in a call to one of the predefined __interruption_points__ with
|
|
interruption enabled.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[heading Member function `priority( int)`]
|
|
|
|
void priority( int) noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`*this` refers to a fiber of execution.]]
|
|
[[Effects:] [set priority for the fiber referenced by `*this`.]]
|
|
[[Throws:] [Nothing]]
|
|
[[Note:] [The meaning of particular `int` values is determined by the specific
|
|
__algo__ passed to [function_link set_scheduling_algorithm]. [class_link
|
|
round_robin] and [class_link round_robin_ws] ignore `fiber::priority()`.]]
|
|
]
|
|
|
|
[member_heading fiber..priority]
|
|
|
|
int priority() const noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`*this` refers to a fiber of execution.]]
|
|
[[Returns:] [priority for the fiber referenced by `*this`.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[#fiber_thread_affinity]
|
|
[heading Member function `thread_affinity( bool)`]
|
|
|
|
void thread_affinity( bool) noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`*this` refers to a fiber of execution.]]
|
|
[[Effects:] [Set thread affinity for the fiber referenced by `*this`.]]
|
|
[[Throws:] [Nothing]]
|
|
[[Note:] ["Thread affinity" is only meaningful for certain scheduler
|
|
algorithms, such as [class_link round_robin_ws]. Many schedulers ignore this
|
|
fiber attribute. With a scheduler that might potentially migrate a fiber from
|
|
its initial thread to another, the value `true` prevents migration: the fiber
|
|
will always run on its current thread. The default is `false`: normally, with
|
|
an applicable scheduler, a fiber is allowed to migrate across threads.]]
|
|
[[See also:] [[ns_function_link this_fiber..thread_affinity]]]
|
|
]
|
|
|
|
[heading Member function `thread_affinity()`]
|
|
|
|
bool thread_affinity() const noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [`*this` refers to a fiber of execution.]]
|
|
[[Returns:] [thread affinity for the fiber referenced by `*this`.]]
|
|
[[Throws:] [Nothing]]
|
|
[[See also:] [[ns_function_link this_fiber..thread_affinity]]]
|
|
]
|
|
|
|
[member_heading fiber..operator safe_bool]
|
|
|
|
operator safe_bool() const noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this` refers to a fiber of execution which has not
|
|
yet terminated, `false` otherwise. Compare to __joinable__, which does not
|
|
distinguish whether the referenced fiber of execution is still running.]]
|
|
[[Throws:] [Nothing]]
|
|
[[See also:] [__joinable__]]
|
|
]
|
|
|
|
[operator_heading fiber..operator_not..operator!]
|
|
|
|
bool operator!() const noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this` does not refer to a fiber of execution or if
|
|
its fiber of execution has terminated, `false` otherwise.]]
|
|
[[Throws:] [Nothing]]
|
|
[[See also:] [[member_link fiber..operator safe_bool], __joinable__]]
|
|
]
|
|
|
|
[member_heading fiber..swap]
|
|
|
|
void swap( fiber & other) noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Exchanges the fiber of execution associated with `*this` and
|
|
`other`, so `*this` becomes associated with the fiber formerly associated with
|
|
`other`, and vice-versa.]]
|
|
[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()`
|
|
prior to the call. `other.get_id()` returns the same value as `this->get_id()`
|
|
prior to the call.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
[function_heading swap]
|
|
|
|
void swap( fiber & l, fiber & r) noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Same as `l.swap( r)`.]]
|
|
]
|
|
|
|
[function_heading set_scheduling_algorithm]
|
|
|
|
void set_scheduling_algorithm( algorithm* scheduler );
|
|
|
|
[variablelist
|
|
[[Effects:] [Directs __boost_fiber__ to use `scheduler`, which must be a
|
|
concrete subclass of __algo__, as the scheduling algorithm for all fibers in
|
|
the current thread.]]
|
|
[[Returns:] [Previous __algo__ instance set for the current thread, 0 if this
|
|
is the first __boost_fiber__ entry point called by the current thread.]]
|
|
[[Note:] [If you want a given thread to use a non-default scheduling
|
|
algorithm, make that thread call `set_scheduling_algorithm()` before any other
|
|
__boost_fiber__ entry point. If no scheduler has been set for the current
|
|
thread by the time __boost_fiber__ needs to use it, the library will
|
|
heap-allocate a default [class_link round_robin] instance for this thread.]]
|
|
[[Note:] [`set_scheduling_algorithm()` does ['not] take ownership of the
|
|
passed `algorithm*`: __boost_fiber__ does not claim responsibility for the
|
|
lifespan of the referenced `scheduler` object. The caller must eventually
|
|
destroy the passed `scheduler`, just as it must allocate it in the first
|
|
place. (Storing the pointer in a `boost::thread_specific_ptr` is one way to
|
|
ensure that the instance is destroyed on thread termination.)]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
|
|
|
|
[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 <boost/fiber/fiber_group.hpp>
|
|
|
|
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]
|
|
|
|
Class `attributes` is used to transfer parameters required to set up a
|
|
fiber's context.
|
|
|
|
#include <boost/fiber/attributes.hpp>
|
|
|
|
struct attributes
|
|
{
|
|
std::size_t size;
|
|
|
|
attributes() BOOST_NOEXCEPT;
|
|
|
|
explicit attributes( std::size_t size_) BOOST_NOEXCEPT;
|
|
};
|
|
|
|
[heading Constructor]
|
|
|
|
attributes();
|
|
attributes( std::size_t size);
|
|
|
|
[variablelist
|
|
[[Effects:] [Parameter `size` determines the stack size.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[endsect] [/ section Class attributes]
|
|
|
|
|
|
[section:this_fiber Namespace this_fiber]
|
|
|
|
namespace boost {
|
|
namespace this_fiber {
|
|
|
|
fibers::fiber::id get_id() noexcept;
|
|
void yield();
|
|
void sleep_until( fibers::clock_type::time_point const& sleep_time);
|
|
template< typename Rep, typename Period >
|
|
void sleep_for( chrono::duration< Rep, Period > const& timeout_duration);
|
|
bool thread_affinity() noexcept;
|
|
void thread_affinity( bool req) noexcept;
|
|
|
|
void interruption_point();
|
|
bool interruption_requested() noexcept;
|
|
bool interruption_enabled() noexcept;
|
|
class disable_interruption;
|
|
class restore_interruption;
|
|
|
|
}}
|
|
|
|
[ns_function_heading this_fiber..get_id]
|
|
|
|
#include <boost/fiber/operations.hpp>
|
|
|
|
fiber::id get_id() noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [An instance of __fiber_id__ that represents the currently
|
|
executing fiber.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..sleep_until]
|
|
|
|
#include <boost/fiber/operations.hpp>
|
|
|
|
void sleep_until( fibers::clock_type & abs_time);
|
|
|
|
[variablelist
|
|
[[Effects:] [Suspends the current fiber until the time point specified by
|
|
`abs_time` has been reached.]]
|
|
[[Throws:] [__fiber_interrupted__ if the current fiber is interrupted.]]
|
|
[[Note:] [`sleep_until()` is one of the predefined __interruption_points__.]]
|
|
[[Note:][The current fiber will not resume before `abs_time`, but there are no
|
|
guarantees about how soon after `abs_time` it might resume.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..sleep_for]
|
|
|
|
#include <boost/fiber/operations.hpp>
|
|
|
|
template< class Rep, class Period >
|
|
void sleep_for( chrono::duration< Rep, Period > const& rel_time);
|
|
|
|
[variablelist
|
|
[[Effects:] [Suspends the current fiber until the time duration specified by
|
|
`rel_time` has elapsed.]]
|
|
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw
|
|
exceptions. __fiber_interrupted__ if the current fiber is interrupted.]]
|
|
[[Note:] [`sleep_for()` is one of the predefined __interruption_points__.]]
|
|
[[Note:][The current fiber will not resume before `rel_time` has elapsed, but
|
|
there are no guarantees about how soon after that it might resume.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..yield]
|
|
|
|
#include <boost/fiber/operations.hpp>
|
|
|
|
void yield();
|
|
|
|
[variablelist
|
|
[[Effects:] [Reliquishes execution control, allowing other fibers to run.]]
|
|
[[Throws:] [__fiber_resource_error__ if an error occurs.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..thread_affinity]
|
|
|
|
#include <boost/fiber/operations.hpp>
|
|
|
|
bool thread_affinity() noexcept;
|
|
void thread_affinity( bool req) noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Set or report [member_link fiber..thread_affinity] for the currently
|
|
running fiber.]]
|
|
[[Throws:] [Nothing.]]
|
|
[[Note:] [[member_link fiber..thread_affinity] is `false` by default.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..interruption_point]
|
|
|
|
#include <boost/fiber/interruption.hpp>
|
|
void interruption_point();
|
|
|
|
[variablelist
|
|
[[Effects:] [Check to see if the current fiber has been interrupted.]]
|
|
[[Throws:] [__fiber_interrupted__ if __interruption_enabled__ and
|
|
__interruption_requested__ both return `true`.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..interruption_requested]
|
|
|
|
#include <boost/fiber/interruption.hpp>
|
|
|
|
bool interruption_requested() noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if interruption has been requested for the current fiber,
|
|
`false` otherwise.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[ns_function_heading this_fiber..interruption_enabled]
|
|
|
|
#include <boost/fiber/interruption.hpp>
|
|
|
|
bool interruption_enabled() noexcept;
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if interruption is enabled for the current fiber,
|
|
`false` otherwise.]]
|
|
[[Throws:] [Nothing.]]
|
|
[[Note:][Interruption is enabled by default.]]
|
|
]
|
|
|
|
[class_heading disable_interruption]
|
|
|
|
#include <boost/fiber/interruption.hpp>
|
|
|
|
class disable_interruption
|
|
{
|
|
public:
|
|
disable_interruption() noexcept;
|
|
~disable_interruption() noexcept;
|
|
disable_interruption(const disable_interruption&) = delete;
|
|
disable_interruption& operator=(const disable_interruption&) = delete;
|
|
};
|
|
|
|
[heading Constructor]
|
|
|
|
disable_interruption() noexcept;
|
|
|
|
[variablelist
|
|
[[Effects:] [Stores the current state of __interruption_enabled__ and disables
|
|
interruption for the current fiber.]]
|
|
[[Postconditions:] [__interruption_enabled__ returns `false` for the current
|
|
fiber.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading Destructor]
|
|
|
|
~disable_interruption() noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same fiber on which `*this` was
|
|
constructed.]]
|
|
[[Effects:] [Restores the state of __interruption_enabled__ for the
|
|
current fiber to the state saved at construction of `*this`.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current fiber returns the
|
|
value stored by the constructor of `*this`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
|
|
[class_heading restore_interruption]
|
|
|
|
#include <boost/fiber/interruption.hpp>
|
|
|
|
class restore_interruption
|
|
{
|
|
public:
|
|
explicit restore_interruption(disable_interruption& disabler) noexcept;
|
|
~restore_interruption() noexcept;
|
|
restore_interruption(const restore_interruption&) = delete;
|
|
restore_interruption& operator=(const restore_interruption&) = delete;
|
|
};
|
|
|
|
[heading Constructor]
|
|
|
|
explicit restore_interruption(disable_interruption& disabler) noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same fiber on which `disabler` was
|
|
constructed.]]
|
|
[[Effects:] [Restores the current state of __interruption_enabled__ for the
|
|
current fiber to that saved in `disabler`.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current fiber returns the
|
|
value stored in the constructor of `disabler`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[heading Destructor]
|
|
|
|
~restore_interruption() noexcept;
|
|
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same fiber on which `*this` was
|
|
constructed.]]
|
|
[[Effects:] [Disables interruption for the current fiber.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current fiber returns
|
|
`false`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
void foo()
|
|
{
|
|
// interruption is enabled
|
|
{
|
|
boost::this_fiber::disable_interruption di;
|
|
// interruption is disabled
|
|
{
|
|
boost::this_fiber::restore_interruption ri( di);
|
|
// interruption now enabled
|
|
} // ri destroyed, interruption disable again
|
|
} // di destructed, interruption state restored
|
|
// interruption now enabled
|
|
}
|
|
|
|
[endsect] [/ section Namespace this_fiber]
|
|
|
|
|
|
[endsect] [/ section Fiber Management]
|