mirror of
https://github.com/boostorg/fiber.git
synced 2026-02-20 14:42:21 +00:00
1265 lines
36 KiB
Plaintext
1265 lines
36 KiB
Plaintext
[/
|
|
(C) Copyright 2007-8 Anthony Williams.
|
|
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:tasklet_management Tasklet Management]
|
|
|
|
[heading Synopsis]
|
|
|
|
Each __tasklet__ class represents a micro-task which will be launched and
|
|
managed by the __scheduler__ class. Objects of type __tasklet__ are copy- and
|
|
moveable.
|
|
|
|
boost::tasklet f; // not-a-tasklet
|
|
|
|
void f()
|
|
{
|
|
boost::tasklet f1( boost::tasklets::make_tasklet( some_fn, boost::tasklet::default_stacksize) );
|
|
boost::tasklet f2( boost::tasklets::make_tasklet( another_fn, boost::tasklet::default_stacksize) );
|
|
|
|
boost::tasklets::scheduler<> s;
|
|
s.submit( f1); // f1 gets copied
|
|
s.submit( boost::move( f2) ); // f2 gets moved
|
|
|
|
std::cout << f1.get_id() << std::endl;
|
|
std::cout << f2.get_id() << std::endl;
|
|
}
|
|
|
|
|
|
[note If tasklets are migrated between threads the code called by a tasklet must
|
|
not use thread-local-storage.]
|
|
|
|
|
|
[heading Launching]
|
|
|
|
A new tasklet is launched by passing an object of a callable type that can be
|
|
invoked with no parameters to the constructor and submiting the tasklet (copy-
|
|
or move-op.) to an instance of __scheduler__. The object is then copied into
|
|
internal storage, and invoked on the newly-created tasklet. 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 of __boost_tasklet__ must ensure
|
|
that the referred-to object outlives the newly-created tasklet.
|
|
|
|
struct callable
|
|
{ void operator()(); };
|
|
|
|
boost::tasklet copies_are_safe()
|
|
{
|
|
callable x;
|
|
return boost::tasklet( x);
|
|
} // x is destroyed, but the newly-created tasklet has a copy, so this is OK
|
|
|
|
boost::tasklet oops()
|
|
{
|
|
callable x;
|
|
return boost::tasklet( boost::ref( x), boost::tasklet::default_stacksize);
|
|
} // x is destroyed, but the newly-created tasklet still has a reference
|
|
// this leads to undefined behaviour
|
|
|
|
If you wish to construct an instance of __tasklet__ with a function or callable
|
|
object that requires arguments to be supplied, this can be done by passing
|
|
additional arguments to the __tasklet__ constructor:
|
|
|
|
void find_the_question( int the_answer);
|
|
|
|
boost::tasklet deep_thought_2( find_the_question, 42, boost::tasklet::default_stacksize);
|
|
|
|
The arguments are ['copied] into the internal tasklet structure: if a reference
|
|
is required, use `boost::ref`, just as for references to callable functions.
|
|
|
|
For convinience `boost::tasklets::make_tasklet()` is provided:
|
|
|
|
boost::tasklet f( boost::tasklets::make_tasklet( new_fn, arg1, arg2, arg3, boost::tasklet::default_stacksize) );
|
|
|
|
Another alternative is to use `scheduler<>::make_tasklet()` which creates and
|
|
stores the new tasklet inside the scheduler.
|
|
|
|
boost::tasklets::scheduler<> sched;
|
|
sched.make_tasklet( new_fn, arg1, arg2, arg3, boost::tasklet_default_stacksize);
|
|
|
|
|
|
[heading Exceptions]
|
|
|
|
Exceptions thrown by the function or callable object passed to the __tasklet__
|
|
constructor are consumed by the framework (if it required to know which
|
|
exceptions was thrown use __future__ and __packaged_task__).
|
|
|
|
[warning Don't use the sjlj exception model. Frame-unwind-tables instead of
|
|
setjmp/longjmp based exception handling should be used.]
|
|
|
|
[heading Joining]
|
|
|
|
In order to wait for a tasklet to finish, the __join__ member functions of the
|
|
__tasklet__ object can be used. __join__ will block the calling tasklet until
|
|
the tasklet represented by the __tasklet__ object has completed.
|
|
If the tasklet has already completed, or the __tasklet__ object represents
|
|
__not_a_tasklet__, then __join__ returns immediately.
|
|
|
|
void some_fn()
|
|
{}
|
|
|
|
void joining_tasklet_fn( boost::tasklet f)
|
|
{ f.join(); }
|
|
|
|
boost:.tasklets::scheduler<> sched;
|
|
boost::tasklet f( some_fn, boost::tasklet_default_stacksize);
|
|
sched.submit_tasklet( f);
|
|
sched.make_tasklet( joining_tasklet, f, boost::tasklet_default_stacksize);
|
|
for (;;)
|
|
{
|
|
while ( sched.run() );
|
|
if ( sched.empty() ) break;
|
|
}
|
|
|
|
|
|
[heading Interruption]
|
|
|
|
A running tasklet can be ['interrupted] by invoking the __interrupt__ member
|
|
function. When the interrupted tasklet next executes one of the specified
|
|
__interruption_points__ (or if it is currently __blocked__ whilst executing one)
|
|
with interruption enabled, then a __tasklet_interrupted__ exception will be
|
|
thrown in the interrupted tasklet. If not caught, this will cause the execution
|
|
of the interrupted tasklet to terminate.
|
|
|
|
If a tasklet wishes to avoid being interrupted, it can create an instance of
|
|
__disable_interruption__. Objects of this class disable interruption for the
|
|
tasklet that created them on construction, and restore the interruption state to
|
|
whatever it was before on destruction:
|
|
|
|
void f()
|
|
{
|
|
// interruption enabled here
|
|
{
|
|
boost::this_tasklet::disable_interruption disabler1;
|
|
// interruption disabled
|
|
{
|
|
boost::this_tasklet::disable_interruption disabler2;
|
|
// interruption still disabled
|
|
} // disabler2 destroyed, interruption state restored
|
|
// interruption still disabled
|
|
} // disabler1 destroyed, interruption state restored
|
|
// interruption now enabled
|
|
}
|
|
|
|
The effects of an instance of __disable_interruption__ can be temporarily
|
|
reversed by constructing an instance of __restore_interruption__, passing in the
|
|
__disable_interruption__ object in question. This will restore the interruption
|
|
state to what it was when the __disable_interruption__ object was constructed,
|
|
and then disable interruption again when the __restore_interruption__ object is
|
|
destroyed.
|
|
|
|
void g()
|
|
{
|
|
// interruption enabled here
|
|
{
|
|
boost::this_tasklet::disable_interruption disabler;
|
|
// interruption disabled
|
|
{
|
|
boost::this_tasklet::restore_interruption restorer( disabler);
|
|
// interruption now enabled
|
|
} // restorer destroyed, interruption disable again
|
|
} // disabler destroyed, interruption state restored
|
|
// interruption now enabled
|
|
}
|
|
|
|
At any point, the interruption state for the current tasklet can be queried by
|
|
calling __interruption_enabled__.
|
|
|
|
|
|
[heading Predefined Interruption Points]
|
|
|
|
The following functions are ['interruption points], which will throw
|
|
__tasklet_interrupted__ if interruption is enabled for the current tasklet, and
|
|
interruption is requested for the current tasklet:
|
|
|
|
* [join_link `boost::tasklet::join()`]
|
|
* [cond_wait_link `boost::tasklets::condition::wait()`]
|
|
* [auto_reset_wait_link `boost::tasklets::auto_reset_event::wait()`]
|
|
* [manual_reset_wait_link `boost::tasklets::manual_reset_event::wait()`]
|
|
* [count_down_wait_link `boost::tasklets::count_down_event::wait()`]
|
|
* __interruption_point__
|
|
|
|
|
|
[heading Tasklet IDs]
|
|
|
|
Objects of class __tasklet_id__ can be used to identify tasklets. Each running
|
|
tasklet has a unique ID obtainable from the corresponding __tasklet__ by calling
|
|
the `get_id()` member function, or by calling `boost::this_tasklet::get_id()`
|
|
from within the tasklet. Objects of class __tasklet_id__ can be copied, and used
|
|
as keys in associative containers: the full range of comparison operators is
|
|
provided. Tasklet IDs can also be written to an output stream using the stream
|
|
insertion operator, though the output format is unspecified.
|
|
|
|
Each instance of __tasklet_id__ either refers to some tasklet, or
|
|
__not_a_tasklet__. Instances that refer to __not_a_tasklet__ compare equal to
|
|
each other, but not equal to any instances that refer to an actual tasklet. The
|
|
comparison operators on __tasklet_id__ yield a total order for every non-equal
|
|
tasklet ID.
|
|
|
|
|
|
[section:tasklet Class `tasklet`]
|
|
|
|
#include <boost/tasklet/tasklet.hpp>
|
|
|
|
class tasklet
|
|
{
|
|
public:
|
|
tasklet();
|
|
~tasklet();
|
|
|
|
template< typename Fn >
|
|
explicit tasklet( Fn fn, std::size_t stack_size);
|
|
|
|
template< typename Fn, typename A1, typename A2,... >
|
|
tasklet( Fn fn, A1 a1, A2 a2,..., std::size_t stack_size);
|
|
|
|
template< typename Fn >
|
|
explicit tasklet( Fn && fn, std::size_t stack_size);
|
|
|
|
// move support
|
|
tasklet( tasklet && x);
|
|
tasklet & operator=( tasklet && x);
|
|
|
|
operator unspecified-bool-type() const;
|
|
|
|
bool operator!() const;
|
|
|
|
void swap( tasklet & other);
|
|
|
|
id get_id() const;
|
|
|
|
bool operator==( tasklet const&) const;
|
|
bool operator!=( tasklet const&) const;
|
|
|
|
bool is_alive() const;
|
|
|
|
int priority() const;
|
|
|
|
void priority( int);
|
|
|
|
void interrupt();
|
|
bool interruption_requested() const;
|
|
|
|
void cancel();
|
|
|
|
void join();
|
|
};
|
|
|
|
void swap( tasklet & lhs, tasklet & rhs);
|
|
|
|
template< typename Fn >
|
|
tasklet make_tasklet( Fn fn, std::size_t stack_size);
|
|
|
|
template< typename Fn, typename A1, typename A2,..., typename A10 >
|
|
tasklet make_tasklet( Fn fn, A1 a1, A2 a2,..., A10 a10, std::size_t stack_size);
|
|
|
|
|
|
[section:default_constructor `tasklet()`]
|
|
[variablelist
|
|
[[Effects:] [Constructs a __tasklet__ instance that refers to
|
|
__not_a_tasklet__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:callable_constructor_stack `template< typename Fn > tasklet( Fn fn, std::size_t stack_size)`]
|
|
[variablelist
|
|
[[Preconditions:] [`Callable` must by copyable.]]
|
|
[[Effects:] [`fn` is copied into storage managed internally by the tasklet
|
|
library, and that copy is invoked on a newly-created tasklet. Second version
|
|
sets the stack-size of the tasklet.]]
|
|
[[Postconditions:] [`*this` refers to the newly created tasklet.]]
|
|
[[Throws:] [__bad_alloc__]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:multiple_argument_constructor `template< typename Fn, typename A1, typename A2,... > tasklet( Fn fn, A1 a1, A2 a2,..., std::size_t stack_size)`]
|
|
[variablelist
|
|
[[Preconditions:] [`Fn` and each `A`n must by copyable or movable.]]
|
|
[[Effects:] [As if `tasklet( boost::bind( fn, a1, a2,...) )`. Consequently,
|
|
`fn` and each `a`n are copied into internal storage for access by the new
|
|
tasklet. Second version additionaly sets the stack-size used by the tasklet.]]
|
|
[[Postconditions:] [`*this` refers to the newly created tasklet.]]
|
|
[[Throws:] [__bad_alloc__]]
|
|
[[Note:] [Currently up to nine additional arguments `a1` to `a9` can be
|
|
specified in addition to the function `fn`.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:destructor `~tasklet()`]
|
|
[variablelist
|
|
[[Effects:] [Destroys `*this`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:get_id `tasklet::id get_id() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to a tasklet, an instance of __tasklet_id__ that
|
|
represents that tasklet. Otherwise returns a default-constructed
|
|
__tasklet_id__.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:join `void join()`]
|
|
[variablelist
|
|
[[Effects:] [Waits for `*this` to complete.]]
|
|
[[Throws:] [__tasklet_interrupted__ if the current tasklet is interrupted.]]
|
|
[[Notes:] [`join()` is one of the predefined __interruption_points__.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:interrupt `void interrupt()`]
|
|
[variablelist
|
|
[[Effects:] [If `*this` refers to a tasklet, request that the tasklet 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:] [__tasklet_moved__ if not a tasklet of execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:interruption_requested `bool interruption_requested()`]
|
|
[variablelist
|
|
[[Effects:] [If `*this` refers to a tasklet, the function returns if the
|
|
interruption of the tasklet was already requested.]]
|
|
[[Throws:] [__tasklet_moved__ if `*this` is not a tasklet of execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:cancel `void cancel()`]
|
|
[variablelist
|
|
[[Effects:] [If `*this` refers to a tasklet, request that the tasklet will be
|
|
canceled the next time it yields its execution.]]
|
|
[[Throws:] [__tasklet_moved__ if `*this` is not a tasklet of execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:is_alive `bool is_alive()`]
|
|
[variablelist
|
|
[[Effects:] [If `*this` refers to a tasklet, the function returns false if the
|
|
tasklet is terminated or not started Otherwise it returns true.]]
|
|
[[Throws:] [__tasklet_moved__ if `*this` is not a tasklet of execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:unspec_operator `operator unspecified-bool-type() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers to a tasklet, the function returns true.
|
|
Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:not_operator `bool operator!() const`]
|
|
[variablelist
|
|
[[Returns:] [If `*this` refers not to a tasklet, the function returns true.
|
|
Otherwise false.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:equals `bool operator==( tasklet const& other) const`]
|
|
[variablelist
|
|
[[Returns:] [`get_id()==other.get_id()`]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:not_equals `bool operator!=( tasklet const& other) const`]
|
|
[variablelist
|
|
[[Returns:] [`get_id()!=other.get_id()`]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:swap `void swap( tasklet & other)`]
|
|
[variablelist
|
|
[[Effects:] [Exchanges the tasklets associated with `*this` and `other`, so
|
|
`*this` is associated with the tasklet associated with `other` prior to the
|
|
call, 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.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:non_member_swap Non-member function `swap()`]
|
|
|
|
#include <boost/tasklet/tasklet.hpp>
|
|
|
|
void swap( tasklet & lhs, tasklet & rhs);
|
|
|
|
[variablelist
|
|
[[Effects:] [[link tasklet.tasklet_management.tasklet.swap `lhs.swap( rhs)`].]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:non_member_make_tasklet Non-member template function `make_tasklet()`]
|
|
|
|
#include <boost/tasklet/tasklet.hpp>
|
|
|
|
template< typename Fn >
|
|
tasklet make_tasklet( Fn fn, std::size_t stack_size);
|
|
|
|
template< typename Fn, typename A1, typename A2,... >
|
|
tasklet make_tasklet( Fn fn, A1 a1, A2 a2,..., std::size_t stack_size);
|
|
|
|
[variablelist
|
|
[[Effects:] [Creates a tasklet.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:id Class `boost::tasklet::id`]
|
|
|
|
#include <boost/tasklet/tasklet.hpp>
|
|
|
|
class tasklet::id
|
|
{
|
|
public:
|
|
id();
|
|
|
|
bool operator==( id const& y) const;
|
|
bool operator!=( id const& y) const;
|
|
bool operator<( id const& y) const;
|
|
bool operator>( id const& y) const;
|
|
bool operator<=( id const& y) const;
|
|
bool operator>=( id const& y) const;
|
|
|
|
template< typename charT, typename traitsT >
|
|
friend std::basic_ostream< charT, traitsT > &
|
|
operator<<( std::basic_ostream<charT, traitsT > & os, id const& x);
|
|
};
|
|
|
|
[section:constructor `id()`]
|
|
[variablelist
|
|
[[Effects:] [Constructs a __tasklet_id__ instance that represents
|
|
__not_a_tasklet__.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:is_equal `bool operator==( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this` and `y` both represent the same tasklet of
|
|
execution, or both represent __not_a_tasklet__, `false` otherwise.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:not_equal `bool operator!=( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this` and `y` represent different tasklets of
|
|
execution, or one represents a tasklet of execution, and the other represent
|
|
__not_a_tasklet__, `false` otherwise.]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:less_than `bool operator<( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`true` if `*this!=y` is `true` and the implementation-defined total
|
|
order of __tasklet_id__ values places `*this` before `y`, `false` otherwise.]]
|
|
[[Throws:] [Nothing]]
|
|
[[Note:] [A __tasklet_id__ instance representing __not_a_tasklet__ will always
|
|
compare less than an instance representing a tasklet of execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:greater_than `bool operator>( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`y<*this`]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:less_than_or_equal `bool operator<=( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`!(y<*this)`]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:greater_than_or_equal `bool operator>=( id const& y) const`]
|
|
[variablelist
|
|
[[Returns:] [`!(*this<y)`]]
|
|
[[Throws:] [Nothing]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:stream_out Non-member template function `operator<<`]
|
|
|
|
template< typename charT, typename traitsT >
|
|
friend std::basic_ostream< charT, traitsT > &
|
|
operator<<( std::basic_ostream<charT, traitsT > & os, id const& x);
|
|
|
|
[variablelist
|
|
[[Effects:] [Writes a representation of the __tasklet_id__ instance `x` to the
|
|
stream `os`, such that the representation of two instances of __tasklet_id__ `a`
|
|
and `b` is the same if `a==b`, and different if `a!=b`.]]
|
|
[[Returns:] [`os`]]
|
|
]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:this_tasklet Namespace `this_tasklet`]
|
|
|
|
[section:get_id Non-member function `get_id()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
tasklet::id get_id();
|
|
}
|
|
|
|
[variablelist
|
|
[[Returns:] [An instance of __tasklet_id__ that represents that currently
|
|
executing tasklet.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:interruption_point Non-member function `interruption_point()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
void interruption_point();
|
|
}
|
|
|
|
[variablelist
|
|
[[Effects:] [Check to see if the current tasklet has been interrupted.]]
|
|
[[Throws:] [__tasklet_interrupted__ if __interruption_enabled__ and
|
|
__interruption_requested__ both return `true`.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:interruption_requested Non-member function `interruption_requested()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
bool interruption_requested();
|
|
}
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if interruption has been requested for the current tasklet,
|
|
`false` otherwise.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:interruption_enabled Non-member function `interruption_enabled()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
bool interruption_enabled();
|
|
}
|
|
|
|
[variablelist
|
|
[[Returns:] [`true` if interruption has been enabled for the current tasklet,
|
|
`false` otherwise.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:cancel Non-member function `cancel()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
void cancel();
|
|
}
|
|
|
|
[variablelist
|
|
[[Effects:] [Cancels the current tasklet.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:non_member_yield Non-member function `yield()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
void yield();
|
|
}
|
|
|
|
[variablelist
|
|
[[Effects:] [Gives up the remainder of the current tasklet's time slice, to
|
|
allow other tasklets to run.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:attaskletexit Non-member template function `at_tasklet_exit()`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
template<typename Callable>
|
|
void at_tasklet_exit(Callable func);
|
|
|
|
[variablelist
|
|
[[Effects:] [A copy of `func` is placed in
|
|
tasklet-specific storage. This copy is invoked when the current tasklet
|
|
exits (even if the tasklet has been interrupted).]]
|
|
[[Postconditions:] [A copy of `func` has been saved for invocation on tasklet
|
|
exit.]]
|
|
[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the copy of the
|
|
function, __tasklet_error__ if any other error occurs within the tasklet
|
|
library. Any exception thrown whilst copying `func` into internal storage.]]
|
|
[[Note:] [This function is *not* called if the tasklet was terminated
|
|
forcefully using platform-specific APIs, or if the tasklet is
|
|
terminated due to a call to `exit()`, `abort()` or
|
|
`std::terminate()`. In particular, returning from `main()` is
|
|
equivalent to call to `exit()`, so will not call any functions
|
|
registered with `at_tasklet_exit()`]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:submit Non-member function `submit_tasklet( tasklet)`]
|
|
|
|
#include <boost/tasklet/utility.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
void submit_tasklet( tasklet);
|
|
}
|
|
|
|
[variablelist
|
|
[[Effects:] [Submits the passed tasklet to the scheduler running the active
|
|
tasklet.]]
|
|
[[Throws:] [__tasklet_error__ if an error occurs.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:disable_interruption Class `disable_interruption`]
|
|
|
|
#include <boost/tasklet/interruption.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
class disable_interruption
|
|
{
|
|
public:
|
|
disable_interruption();
|
|
~disable_interruption();
|
|
};
|
|
}
|
|
|
|
`boost::this_tasklet::disable_interruption` disables interruption for the
|
|
current tasklet on construction, and restores the prior interruption state on
|
|
destruction. Instances of `disable_interruption` cannot be copied or moved.
|
|
|
|
[section:constructor `disable_interruption()`]
|
|
[variablelist
|
|
[[Effects:] [Stores the current state of __interruption_enabled__ and disables
|
|
interruption for the current tasklet.]]
|
|
[[Postconditions:] [__interruption_enabled__ returns `false` for the current
|
|
tasklet.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:destructor `~disable_interruption()`]
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same tasklet from which `*this` was
|
|
constructed.]]
|
|
[[Effects:] [Restores the current state of __interruption_enabled__ for the
|
|
current tasklet to that prior to the construction of `*this`.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current tasklet returns the
|
|
value stored in the constructor of `*this`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:restore_interruption Class `restore_interruption`]
|
|
|
|
#include <boost/tasklet/interruption.hpp>
|
|
|
|
namespace this_tasklet
|
|
{
|
|
class restore_interruption
|
|
{
|
|
public:
|
|
explicit restore_interruption(disable_interruption& disabler);
|
|
~restore_interruption();
|
|
};
|
|
}
|
|
|
|
On construction of an instance of `boost::this_tasklet::restore_interruption`,
|
|
the interruption state for the current tasklet is restored to the interruption
|
|
state stored by the constructor of the supplied instance of
|
|
__disable_interruption__. When the instance is destroyed, interruption is again
|
|
disabled. Instances of `restore_interruption` cannot be copied or moved.
|
|
|
|
[section:constructor `explicit restore_interruption(disable_interruption& disabler)`]
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same tasklet from which `disabler`
|
|
was constructed.]]
|
|
[[Effects:] [Restores the current state of __interruption_enabled__ for the
|
|
current tasklet to that prior to the construction of `disabler`.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current tasklet returns the
|
|
value stored in the constructor of `disabler`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:destructor `~restore_interruption()`]
|
|
[variablelist
|
|
[[Preconditions:] [Must be called from the same tasklet from which `*this` was
|
|
constructed.]]
|
|
[[Effects:] [Disables interruption for the current tasklet.]]
|
|
[[Postconditions:] [__interruption_enabled__ for the current tasklet returns
|
|
`false`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:scheduler Scheduler]
|
|
|
|
[heading Synopsis]
|
|
|
|
The template __scheduler__ is responsible for managing and scheduling of
|
|
tasklets passed to it. The scheduling algorithm is provided as an template
|
|
argument to __scheduler__ (default is __round_robin__). The class implementing
|
|
the scheduling algorithm must derive from class __strategy__. It is possible to
|
|
migrate tasklets between schedulers.
|
|
|
|
[note If the tasklet is not thread-affine (using thread-local-storage) it can be
|
|
migrated to a scheduler running in another thread.]
|
|
|
|
Usally __scheduler__ will be invoked until all tasklets are scheduled and
|
|
finished.
|
|
|
|
boost::tasklets::scheduler<> sched;
|
|
sched.make_tasklet( some_fn);
|
|
|
|
for (;;)
|
|
{
|
|
while ( sched.run() );
|
|
if ( sched.empty() ) break;
|
|
}
|
|
|
|
|
|
[section:scheduler Template `template< typename Strategy > scheduler`]
|
|
|
|
#include <boost/tasklet/scheduler.hpp>
|
|
|
|
template< typename Strategy >
|
|
class scheduler
|
|
{
|
|
public:
|
|
scheduler();
|
|
|
|
~scheduler();
|
|
|
|
bool run();
|
|
|
|
bool empty();
|
|
|
|
std::size_t size();
|
|
|
|
std::size_t ready();
|
|
|
|
void submit_tasklet( tasklet);
|
|
|
|
template< typename Fn >
|
|
void make_tasklet( Fn fn, std::size_t stack_size);
|
|
|
|
template< typename Fn >
|
|
void make_tasklet( Fn && fn, std::size_t stack_size);
|
|
|
|
template< typename Fn, typename A1, typename A2,..., typename A10 >
|
|
void make_tasklet( Fn fn, A0 a0, A1 a1,..., A10 a10, std:size_t stack_size);
|
|
|
|
void migrate_tasklet( tasklet f);
|
|
|
|
template< typename OtherStrategy >
|
|
void migrate_tasklet( tasklet::id const& id, scheduler< OtherStrategy & sched);
|
|
};
|
|
|
|
|
|
[section:ctor `scheduler()`]
|
|
[variablelist
|
|
[[Effects:] [Creates an object of type scheduler< Strategy >.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:dtor `~scheduler()`]
|
|
[variablelist
|
|
[[Effects:] [Detaches all managed tasklets and destroys the scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:run `bool run()`]
|
|
[variablelist
|
|
[[Effects:] [Executes a tasklet from the internal storage and removes terminated
|
|
tasklets. The function returns `true` if a tasklet could be executed or a
|
|
terminated tasklet could be removed - otherwise `false`.]]
|
|
[[Throws:] [__system_error__ if a system call failed.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:empty `bool empty()`]
|
|
[variablelist
|
|
[[Effects:] [Returns `true` if the scheduler contains tasklets (maybe runnable
|
|
or waiting).]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:size `std::size_t size()`]
|
|
[variablelist
|
|
[[Effects:] [Returns how many tasklets the scheduler contains (maybe runnable or
|
|
waiting).]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:ready `std::size_t ready()`]
|
|
[variablelist
|
|
[[Effects:] [Returns how many tasklets are ready to run in the scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:submit_tasklet `void submit_tasklet( tasklet f)`]
|
|
[variablelist
|
|
[[Effects:] [This function stores the passed tasklet in the scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:make_tasklet2 `template< typename Fn > void make_tasklet( Fn fn, std::size_t stack_size)`]
|
|
[variablelist
|
|
[[Effects:] [The functions create a tasklet which gets stored in the internal
|
|
structures from scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:make_tasklet3 `template< typename Fn, typename A1, typename A2,..., typename A10 > void make_tasklet( Fn fn, A0 a0, A1 a1,..., A10 a10, std::size_t stack_size)`]
|
|
[variablelist
|
|
[[Effects:] [The functions create a tasklet which gets stored in the internal
|
|
structures from scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:migrate_tasklet `void migrate_tasklet( tasklet f)`]
|
|
[variablelist
|
|
[[Effects:] [The tasklet will be migrated to the scheduler.]]
|
|
[[Throws:] [Throws __tasklet_moved__, tasklet_error, scheduler_error.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:migrate_tasklet_t `template< typename OtherStrategy > void migrate_tasklet( tasklet::id const& id, scheduler< OtherStrategy > & sched)`]
|
|
[variablelist
|
|
[[Effects:] [The tasklet will be migrated to the scheduler.]]
|
|
[[Throws:] [Throws __tasklet_moved__, tasklet_error, scheduler_error.]]
|
|
]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:strategy Strategy]
|
|
|
|
[heading Synopsis]
|
|
|
|
The template __scheduler__ accepts the implementation of the scheduling
|
|
algorithm as a template argument (currently __round_robin__ is the choosen as
|
|
the default). Each class destined to implement a scheduling algorithm must
|
|
derive from __strategy__. The member `active_tasklet` holds the current
|
|
(running) tasklet and `master_tasklet` executes the scheduling logic.
|
|
|
|
|
|
[section:strategy Class `strategy`]
|
|
|
|
#include <boost/tasklet/strategy.hpp>
|
|
|
|
class strategy
|
|
{
|
|
protected:
|
|
static __thread tasklet * active_tasklet;
|
|
|
|
void attach( tasklet &);
|
|
void detach( tasklet &);
|
|
|
|
void call( tasklet &);
|
|
void yield( tasklet &);
|
|
|
|
void enable_interruption( tasklet &);
|
|
bool interruption_enabled( tasklet const&);
|
|
|
|
bool in_state_not_started( tasklet const&);
|
|
bool in_state_ready( tasklet const&);
|
|
bool in_state_running( tasklet const&);
|
|
bool in_state_wait_for_tasklet( tasklet const&);
|
|
bool in_state_wait_for_object( tasklet const&);
|
|
bool in_state_terminated( tasklet const&);
|
|
|
|
void set_state_ready( tasklet &);
|
|
void set_state_running( tasklet &);
|
|
void set_state_wait_for_tasklet( tasklet &);
|
|
void set_state_wait_for_object( tasklet &);
|
|
void set_state_terminated( tasklet &);
|
|
|
|
public:
|
|
strategy();
|
|
|
|
virtual ~strategy();
|
|
virtual void add( tasklet) = 0;
|
|
virtual void join( tasklet::id const&) = 0;
|
|
virtual void interrupt( tasklet::id const&) = 0;
|
|
virtual void reschedule( tasklet::id const&) = 0;
|
|
virtual void cancel( tasklet::id const&) = 0;
|
|
virtual void yield( tasklet::id const&) = 0;
|
|
virtual void wait_for_object( object::id const&, spin_mutex::scoped_lock &) = 0;
|
|
virtual void object_notify_one( object::id const&) = 0;
|
|
virtual void object_notify_all( object::id const&) = 0;
|
|
virtual tasklet release( tasklet::id const&) = 0;
|
|
virtual void migrate( tasklet) = 0;
|
|
virtual void detach_all() = 0;
|
|
virtual bool run() = 0;
|
|
virtual bool empty() = 0;
|
|
virtual std::size_t size() = 0;
|
|
virtual std::size_t ready() = 0;
|
|
};
|
|
|
|
|
|
[section:attach `void attach( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function in order to register the scheduler in
|
|
internal storage from the tasklet.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:detach `void detach( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function in order to unregister the scheduler in
|
|
internal storage from the tasklet.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:call `void call( tasklet & f)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function calls tasklet `f`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:yield2 `void yield( tasklet & f)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function yield tasklet `f`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:enable_interruption `void enable_interruption( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function enables interruption on the tasklet.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:interruption_enabled `bool interruption_enabled( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if interruption is enabled on the
|
|
tasklet.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_not_started `bool in_state_not_started( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`started`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_ready `bool in_state_ready( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`ready`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_running `bool in_state_running( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`running`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_wait_for_tasklet `bool in_state_wait_for_tasklet( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`wait for tasklet`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_wait_for_object `bool in_state_wait_for_object( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`wait for object`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:in_state_terminated `bool in_state_terminated( tasklet const&)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function tests if the tasklet is in the state
|
|
`terminated`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:set_state_ready `void set_state_ready( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function sets the state of the tasklet to
|
|
`ready`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:set_state_running `void set_state_running( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function sets the state of the tasklet to
|
|
`running`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:set_state_wait_for_tasklet `void set_state_wait_for_tasklet( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function sets the state of the tasklet to
|
|
`wait for tasklet`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:set_state_wait_for_object `void set_state_wait_for_object( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function sets the state of the tasklet to
|
|
`wait for object`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:set_state_terminated `void set_state_terminated( tasklet &)`]
|
|
[variablelist
|
|
[[Effects:] [Protected member function sets the state of the tasklet to
|
|
`terminated`.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:ctor `strategy()`]
|
|
[variablelist
|
|
[[Effects:] [Creates an object of type strategy and initializes the
|
|
master_tasklet member.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:add `virtual void add( tasklet) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet was not assigned to another scheduler.]]
|
|
[[Effects:] [Add a tasklet to the scheduler.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:join `virtual void join( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet belongs to this scheduler.]]
|
|
[[Effects:] [The active tasklet will yield until the tasklet identified by the
|
|
id has finished its
|
|
execution or was interrupted.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:interrupt `virtual void interrupt( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet belongs to this scheduler.]]
|
|
[[Effects:] [The tasklet identified by the id will be interrupted by its next
|
|
execution.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:reschedule `virtual void reschedule( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet belongs to this scheduler.]]
|
|
[[Effects:] [The scheduling-algorithm will be applied uppon the tasklet
|
|
identified by the id again.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:cancel `virtual void cancel( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet belongs to this scheduler.]]
|
|
[[Effects:] [The tasklet with passed identifier will be stopped, e.g. removed
|
|
from the run-queue.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:yield1 `virtual void yield( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Precondition:] [Tasklet is the active tasklet.]]
|
|
[[Effects:] [Yield active tasklet and switch back to `master_tasklet` in order
|
|
to schedule another tasklet from the internal storage.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:wait_for_object `virtual void wait_for_object( object::id const&, spin_mutex::scoped_lock &) = 0`]
|
|
[variablelist
|
|
[[Effects:] [The active tasklet waits on object until notified.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:object_notify_one `virtual void object_notify_one( object::id const&) = 0`]
|
|
[variablelist
|
|
[[Effects:] [Notify one tasklet waiting on the object. The tasklet gets ready
|
|
for scheduling.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:object_notify_all `virtual void object_notify_all( object::id const&) = 0`]
|
|
[variablelist
|
|
[[Effects:] [Notify all tasklets waiting on the object. The tasklets get ready
|
|
for scheduling.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:release `virtual void release( tasklet::id const&) = 0`]
|
|
[variablelist
|
|
[[Postcondition:] [The tasklet is not terminated or waits on tasklet or
|
|
object.]]
|
|
[[Effects:] [Release tasklet from scheduler.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:migrate `virtual void migrate( tasklet) = 0`]
|
|
[variablelist
|
|
[[Postcondition:] [The tasklet is not already managed by scheduler.]]
|
|
[[Effects:] [Adds tasklet to scheduler.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:detach_all `virtual void detach_all() = 0`]
|
|
[variablelist
|
|
[[Effects:] [Detaches all managed tasklets from this.]]
|
|
]
|
|
[endsect]
|
|
|
|
|
|
[section:run `virtual bool run() = 0`]
|
|
[variablelist
|
|
[[Effects:] [Executes a tasklet from the internal storage and removes terminated
|
|
tasklets. The function returns `true` if a tasklet could be executed or a
|
|
terminated tasklet could be removed - otherwise `false`.]]
|
|
[[Throws:] [__system_error__ if a system call failed.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:empty `virtual bool empty() = 0`]
|
|
[variablelist
|
|
[[Effects:] [Returns `true` if the scheduler contains tasklets (maybe runnable
|
|
or waiting).]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:size `virtual std::size_t size() = 0`]
|
|
[variablelist
|
|
[[Effects:] [Returns how many tasklets the scheduler contains (maybe runnable or
|
|
waiting).]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[section:ready `virtual std::size_t ready() = 0`]
|
|
[variablelist
|
|
[[Effects:] [Returns how many tasklets are ready to run in the scheduler.]]
|
|
[[Throws:] [Nothing.]]
|
|
]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:round_robin Class `round_robin`]
|
|
|
|
The class `round_robin` derives from __strategy__ and implements a simple
|
|
round-robin scheduling-algorithm. It does not make use of tasklet-priorities.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|