Advanced - enter()/exit()#
When tmc::enter(Executor) is called, the task will be resumed on Executor, and it will return a scope object that captures the current executor and priority.
This can be used to later exit() the scope and return to the previous executor and priority.
// assume we start on the cpu executor here
auto scope = co_await tmc::enter(other_exec);
// do something on the other executor
co_await scope.exit();
// we are back on the cpu executor now, with our original priority
Further customizations can be applied to the enter() and exit() calls.
The enter() awaitable supports with_priority().
The exit() awaitable supports resume_on() and with_priority().
Examples:
// assume we start on the cpu executor here, at priority 0
auto scope = co_await tmc::enter(other_exec).with_priority(1);
// we are now running on other_exec, at priority 1
co_await scope.exit().resume_on(third_exec).with_priority(2);
// we are now running on third_exec, at priority 2
API Reference#
-
template<typename E>
inline aw_ex_scope_enter<E> tmc::enter(E &Executor)# Returns an awaitable that suspends the current task and resumes it in the target executor’s context. It may be resumed on a different thread than the one calling enter(). This is idempotent, and is similar in effect to
co_await resume_on(exec);, but additionally saves the current priority so that whenexit()is called, the original priority will be restored. This holds true even if you callenter().with_priority():auto originalExec = tmc::current_executor(); assert(tmc::current_priority() == 0); auto scope = co_await tmc::enter(some_ex).with_priority(1); assert(tmc::current_executor() == some_ex.type_erased()); assert(tmc::current_priority() == 1); co_await scope.exit(); assert(tmc::current_executor() == originalExec); assert(tmc::current_priority() == 0);
exit()also offers thewith_priority()andresume_on()customizations that let you modify this behavior when exiting.
-
template<typename E>
inline aw_ex_scope_enter<E> tmc::enter(E *Executor)# A convenience function identical to tmc::enter(E& exec)
-
template<typename E>
class aw_ex_scope_enter : private tmc::detail::AwaitTagNoGroupAsIs, public tmc::detail::with_priority_mixin<aw_ex_scope_enter<E>># The awaitable type returned by
tmc::enter().Public Functions
-
inline bool await_ready() const noexcept#
Always suspends.
-
inline std::coroutine_handle await_suspend(std::coroutine_handle<> Outer) noexcept#
Switch this task to the target executor.
-
inline aw_ex_scope_exit<E> await_resume() noexcept#
Returns an
aw_ex_scope_exitwith anexit()method that can be called to exit the executor, and resume this task back on its original executor.
-
inline bool await_ready() const noexcept#
-
template<typename E>
class aw_ex_scope_exit : private tmc::detail::AwaitTagNoGroupAsIs, public tmc::detail::resume_on_mixin<aw_ex_scope_exit<E>>, public tmc::detail::with_priority_mixin<aw_ex_scope_exit<E>># The awaitable type returned by
co_await tmc::enter(). Callco_await this.exit()to exit the executor scope.Public Functions
-
inline aw_ex_scope_exit &&exit()#
Returns an awaitable that can be co_await’ed to exit the executor scope. This is idempotent. (Not strictly necessary - you can just
co_await std::move(*this);directly - but makes code a bit easier to understand.)
-
inline bool await_ready() const noexcept#
Always suspends.
-
inline void await_suspend(std::coroutine_handle<> Outer) noexcept#
Post this task to the continuation executor.
-
inline aw_ex_scope_exit &&exit()#