this_fiber


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.

Preconditions

*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).

See also

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.