Integrating External Executors#

Setting the Default Executor#

When tmc::spawn*() is called, the work is typically submitted to the current thread’s executor (tmc::detail::this_thread::executor). If the current thread is an external thread, it won’t be configured with an executor. You can set a default executor which will be used as a fallback in this situation. You only need to call tmc::set_default_executor() once to enable this globally.

inline void tmc::set_default_executor(tmc::ex_any *Executor)#

You only need to set this if you are planning to integrate TMC with external threads of execution that don’t configure tmc::detail::this_thread::executor.

If a TMC function that submits work to the current executor implicitly, such as spawn(), is invoked:

  • on a non-TMC thread that has not set tmc::detail::this_thread::executor

  • without explicitly specifying an executor via .run_on() / .resume_on()

then that function will use this default executor (instead of deferencing nullptr and crashing).

template<typename Exec>
inline void tmc::set_default_executor(Exec &Executor)#

You only need to set this if you are planning to integrate TMC with external threads of execution that don’t configure tmc::detail::this_thread::executor.

If a TMC function that submits work to the current executor implicitly, such as spawn(), is invoked:

  • on a non-TMC thread that has not set tmc::detail::this_thread::executor

  • without explicitly specifying an executor via .run_on() / .resume_on()

then that function will use this default executor (instead of deferencing nullptr and crashing).

template<typename Exec>
inline void tmc::set_default_executor(Exec *Executor)#

You only need to set this if you are planning to integrate TMC with external threads of execution that don’t configure tmc::detail::this_thread::executor.

If a TMC function that submits work to the current executor implicitly, such as spawn(), is invoked:

  • on a non-TMC thread that has not set tmc::detail::this_thread::executor

  • without explicitly specifying an executor via .run_on() / .resume_on()

then that function will use this default executor (instead of deferencing nullptr and crashing).

Fully Integrating#

External libraries or users may provide a type that fully satisfies the concept of an “executor” by implementing a specialization of the tmc::detail::executor_traits struct. Additionally, they must implement the following behaviors:

  • Threads that participate in the executor should set the value of tmc::detail::this_thread::executor.

If all threads of execution implement this behavior, then tmc::external::set_default_executor() is not necessary.

The members of the tmc::detail::executor_traits struct are described below. Also see the docs for tmc::work_item.

template <> struct tmc::detail::executor_traits<your_executor> {
   static void post(your_executor& ex, tmc::work_item&& Item, size_t Priority);

   // Iter will be a forward iterator of tmc::work_item.
   template <typename Iter>
   static void post_bulk(your_executor& ex, Iter&& Items, size_t Count, size_t Priority);

   static tmc::ex_any* type_erased(your_executor& ex);

   static std::coroutine_handle<> task_enter_context(
      your_executor& ex, std::coroutine_handle<> Outer, size_t Priority
   );
};

Example Implementation#

A complete, minimal implementation of tmc::detail::executor_traits is available in the external_executor example.