| Home | Libraries | People | FAQ | More

## Proposed Standard Executors

Boost.Asio provides a complete implementation of the proposed standard executors, as described in P0443r13, P1348r0, and P1393r0.

Just as with executors under the Networking TS model, a standard executor represents a policy as to how, when, and where a piece of code should be executed. Most existing code should continue to work with little or no change.

#### Standard Executor Implementations in Boost.Asio

The `io_context::executor_type`, `thread_pool::executor_type`, `system_executor`, and `strand` executors meet the requirements for the proposed standard executors. For compatibility, these classes also meet the requirements for the Networking TS model of executors.

#### Standard Executor Use in Boost.Asio

All I/O objects such as `ip::tcp::socket`, asynchronous operations, and utilities including `dispatch`, `post`, `defer`, `get_associated_executor`, `bind_executor`, `make_work_guard`, `spawn`, `co_spawn`, `async_compose`, `use_future`, etc., can interoperate with both proposed standard executors, and with Networking TS executors. Boost.Asio's implementation determines at compile time which model a particular executor meets; the proposed standard executor model is used in preference if both are detected.

Support for the existing Networking TS model of executors can be disabled by defining `BOOST_ASIO_NO_TS_EXECUTORS`.

#### Polymorphic I/O Executor

The `any_io_executor` type alias is the default runtime-polymorphic executor for all I/O objects. This type alias points to the `execution::any_executor<>` template with a set of supportable properties specified for use with I/O.

This new name may break existing code that directly uses the old polymorphic wrapper, `executor`. If required for backward compatibility, `BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT` can be defined, which changes the `any_io_executor` type alias to instead point to the `executor` polymorphic wrapper.

#### Implementing a Minimal I/O Executor

Standard executor properties make what were previously hard requirements on an executor (such as work counting, or the ability to distinguish between `post`, `dispatch`, and `defer`) into optional facilities. With this relaxation, the minimal requirements for an I/O executor are:

- Conformance to the `executor` concept.
- The ability to query the `execution::context` property, with the result being `execution_context&` or a reference to a class that is derived from `execution_context`.
- The `execute` operation having, at minimum, the `execution::blocking.never` semantic.

The following example shows a minimal I/O executor. Given a queue submission operation implemented elsewhere:

    queue_t queue_create();
    template <typename F> void queue_submit(queue_t q, F f);

the executor may be defined as follows:

    struct minimal_io_executor
    {
      boost::asio::execution_context* context_;
      queue_t queue_;

      bool operator==(const minimal_io_executor& other) const noexcept
      {
        return context_ == other.context_ && queue_ == other.queue_;
      }

      bool operator!=(const minimal_io_executor& other) const noexcept
      {
        return !(*this == other);
      }

      boost::asio::execution_context& query(
          boost::asio::execution::context_t) const noexcept
      {
        return *context_;
      }

      static constexpr boost::asio::execution::blocking_t::never_t query(
          boost::asio::execution::blocking_t) noexcept
      {
        // This executor always has blocking.never semantics.
        return boost::asio::execution::blocking.never;
      }

      template <class F>
      void execute(F f) const
      {
        queue_submit(queue_, std::move(f));
      }
    };

This executor may be created as follows:

    boost::asio::execution_context context;
    queue_t queue = queue_create();
    minimal_io_executor executor{&context, queue};

and then used with I/O objects:

    boost::asio::ip::tcp::acceptor acceptor(executor);

or assigned into the `any_io_executor` polymorphic wrapper:

    boost::asio::any_io_executor poly_executor = executor;

#### Traits for Deducing Conformance to the Executor Concept

Older C++ standards and compilers require some assistance to determine whether an executor implementation conforms to the `executor` concept and type requirements. This is achieved through specialisation of traits. The following code shows a specialisation of these traits for the `minimal_io_executor` example from above:

    namespace boost { namespace asio {
    namespace traits {

    #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)

    template <typename F>
    struct execute_member<minimal_io_executor, F>
    {
      static constexpr bool is_valid = true;
      static constexpr bool is_noexcept = true;
      typedef void result_type;
    };

    #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
    #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)

    template <>
    struct equality_comparable<minimal_io_executor>
    {
      static constexpr bool is_valid = true;
      static constexpr bool is_noexcept = true;
    };

    #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
    #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)

    template <>
    struct query_member<minimal_io_executor,
        boost::asio::execution::context_t>
    {
      static constexpr bool is_valid = true;
      static constexpr bool is_noexcept = true;
      typedef boost::asio::execution_context& result_type;
    };

    #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
    #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)

    template <typename Property>
    struct query_static_constexpr_member<minimal_io_executor, Property,
        typename enable_if<
          std::is_convertible<Property, boost::asio::execution::blocking_t>::value
        >::type>
    {
      static constexpr bool is_valid = true;
      static constexpr bool is_noexcept = true;
      typedef boost::asio::execution::blocking_t::never_t result_type;
      static constexpr result_type value() noexcept { return result_type(); }
    };

    #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)

    } // namespace traits
    } } // namespace boost::asio

Boost.Asio uses an extensive set of traits to implement all of the proposed standard executor functionality on older C++ standards. These traits may be found under the `boost/asio/traits` include directory.