class fiber::this_fiber;
To have access to a this_fiber
object, just spawn a fiber and an object of
this type will be created for you. You can copy and pass it around freely to
other functions as you wish, but you should only use its methods within the
fiber context (i.e. within the fiber execution stack) that created it.
Important
|
fiber is a typedef for
basic_fiber<boost::asio::io_context::strand> . Strand below will refer to the
template argument of the instantiation used.
|
Member-functions
operator[]()
this_fiber operator[](boost::system::error_code& ec) const;
this_fiber operator[](std::nullptr_t) const;
Will return a new this_fiber
object which will fill ec
instead throwing an
exception when used as a completion token argument for async_*
functions. If
nullptr
is passed, then the returned object will have the default
exception-throwing behaviour.
Example:
void start(fiber::this_fiber this_fiber)
{
boost::asio::steady_timer timer{this_fiber.get_executor().context()};
timer.expires_after(std::chrono::seconds(1));
boost::system::error_code ec;
timer.async_wait(this_fiber[ec]);
if (ec) {
// ...
operator=()
this_fiber& operator=(const this_fiber& o);
Assigns o
's error_code
reporting behaviour (see operator[]()
) to
*this
.
*this
and o
are handles for the same fiber.
get_executor()
Strand get_executor() const;
Returns the strand associated with this fiber. You can set the strand associated
with the fiber by passing the desired strand by the time construct
fiber
. User-code running on this fiber will always be executed through this
strand. Implementation details might or might not move the fiber through
different strands to perform some synchronization but no user code will be
called while the fiber is in a foreign strand.
yield()
void yield();
Re-schedules the fiber to be executed soon. Use this function to yield CPU-time to other fibers if you don’t want to block the thread while doing intensive CPU work for a long period of time.
with_intr()
template<class... Args>
unspecified with_intr(Args&&... args);
Calls interrupter_for<typename std::decay<Args>::type…>::assign(*this,
std::forward<Args>(args)…)
and returns a completion token that can be used in
asynchronous operations. When the operation finishes, calls
interrupter_for<typename std::decay<Args>::type…>::on_result()
(before the
result is returned to the caller of the async operation).
Return type is unspecified.
See interruption(7) for details.
{forbid,allow}_suspend()
void forbid_suspend();
void allow_suspend();
These functions are in the same level of usefulness of an assert()
directive. They’re only useful if there are comprehensive test cases and they
expand to no-ops if compiled with NDEBUG
.
Still, the use of these functions may make the code more readable. And some tools may be developed to understand these blocks and do some simple static analysis.
A call to forbid_suspend()
will put the fiber in the state of
suspension-disallowed and any attempt to suspend the fiber while it is in this
state will call std::abort()
.
forbid_suspend()
may be called multiple times. A matching number of calls to
allow_suspend()
will put the fiber out of the suspension-disallowed
state. You must not call allow_suspend()
if there was no prior call to
forbid_suspend()
.
this_fiber
's copy constructor will also trigger a call to std::abort()
if
the fiber is in the suspension-disallowed
state as the copy constructor is
only used to make calls to functions that potentially suspend and this defensive
behaviour will make you less dependant of fully comprehensive tests.
See also the
assert_excl_strand_ref(3)
RAII
helper.
local()
template<class T, class... Args>
T& local(Args&&... args);
Access fiber local storage. If T
is not in fiber-local storage, constructs T
forwarding args
. T
will be destructed when fiber finishes.
Once T
is in the fiber-local storage, it’ll only be destructed once the fiber
finishes and it’ll remain at a stable memory location throughout its lifetime,
so you can safely cache pointers to it. That’s also the reason why no
reset_*()
function to clear local data is provided.
- Requires
-
noexcept(~T())
- Exception safety
-
Provides strong exception guarantees.
Member variables
interrupter
std::function<void()>& interrupter;
When you interrupt a fiber (i.e. fiber::interrupt()
), a generic interruption
trigger will be executed to wake-up the fiber and throw a fiber_interrupted
exception. However, this behaviour won’t immediately cancel pending IO
requests. Suppose your fiber is suspended in the following point when an
interruption request arrives:
void start(fiber::this_fiber this_fiber)
{
boost::asio::steady_timer timer{this_fiber.get_executor().context()};
timer.expires_after(std::chrono::seconds(1));
try {
timer.async_wait(this_fiber);
You might postpone interruption fulfilment to later by having some code like this:
} catch (const fiber_interrupted&) {
[[maybe_unused]]
fiber::this_fiber::disable_interruption di{this_fiber};
// some time (time != CPU time) consuming task here
By this point, the timer
object is still alive and its pending request hasn’t
been cancelled yet — it’d be automatically cancelled by letting the destructor
run.
You can fix this situation by having a custom interrupter to wake-up the fiber when an interruption request arrives. Just assign a value to this variable right before reaching a fiber suspension point.
Note
|
It’s only useful to modify this variable for IO requests (i.e. async_*
functions) as the default interrupter will do fine for this_fiber.yield() ,
fib.join(this_fiber) and other synchronization techniques shown here.
|
Always filling a custom interrupter is also the only way you can have a robust
program that never discards the result of an operation whose side-effects
already occurred (you can force fulfillment at every call-site by defining
TRIAL_IOFIBER_DISABLE_DEFAULT_INTERRUPTER
).
Nested types
disable_interruption
Saves current interruption enabled state (and disable interruptions) on construction and restores it on destruction. It’s non-moveable and non-copyable.
See interruption(7)
for more.
restore_interruption
Temporarily reverses the effects of the disable_interruption
object. It’s
non-moveable and non-copyable.
See interruption(7)
for more.