13 Asynchronous model [async]

13.7 Class execution_context [async.exec.ctx]

Class execution_context implements an extensible, type-safe, polymorphic set of services, indexed by service type.

namespace std {
namespace experimental {
namespace net {
inline namespace v1 {

  class execution_context
  {
  public:
    class service;

    // [async.exec.ctx.cons], construct / copy / destroy:

    execution_context();
    execution_context(const execution_context&) = delete;
    execution_context& operator=(const execution_context&) = delete;
    virtual ~execution_context();

    // [async.exec.ctx.ops], execution context operations:

    void notify_fork(fork_event e);

  protected:

    // [async.exec.ctx.protected], execution context protected operations:

    void shutdown() noexcept;
    void destroy() noexcept;
  };

  // service access:
  template<class Service> typename Service::key_type&
    use_service(execution_context& ctx);
  template<class Service, class... Args> Service&
    make_service(execution_context& ctx, Args&&... args);
  template<class Service> bool has_service(const execution_context& ctx) noexcept;
  class service_already_exists : public logic_error { };

} // inline namespace v1
} // namespace net
} // namespace experimental
} // namespace std

Access to the services of an execution_context is via three function templates, use_service, make_service and has_service.

In a call to use_service<Service>, the type argument chooses a service, identified by Service::key_type, from a set of services in an execution_context. If the service is not present in the execution_context, an object of type Service is created and added to the execution_context. A program can check if an execution_context implements a particular service with the function template has_service<Service>.

Service objects may be explicitly added to an execution_context using the function template make_service<Service>. If the service is already present, make_service exits via an exception of type service_already_exists.

Once a service reference is obtained from an execution_context object by calling use_service, that reference remains usable until a call to destroy().

If a call to a specialization of use_service or make_service recursively calls another specialization of use_service or make_service which would choose the same service (identified by key_type) from the same execution_context, then the behavior is undefined. [ Note: Nested calls to specializations for different service types are well-defined.  — end note ]

13.7.1 execution_context constructor [async.exec.ctx.cons]

execution_context();

Effects: Creates an object of class execution_context which contains no services. [ Note: An implementation can preload services of internal service types for its own use.  — end note ]

13.7.2 execution_context destructor [async.exec.ctx.dtor]

~execution_context();

Effects: Destroys an object of class execution_context. Performs shutdown() followed by destroy().

13.7.3 execution_context operations [async.exec.ctx.ops]

void notify_fork(fork_event e);

Effects: For each service object svc in the set:

  • If e == fork_event::prepare, performs svc->notify_fork(e) in reverse order of addition to the set.

  • Otherwise, performs svc->notify_fork(e) in order of addition to the set.

13.7.4 execution_context protected operations [async.exec.ctx.protected]

void shutdown() noexcept;

Effects: For each service object svc in the execution_context set, in reverse order of addition to the set, performs svc->shutdown(). For each service in the set, svc->shutdown() is called only once irrespective of the number of calls to shutdown on the execution_context.

void destroy() noexcept;

Effects: Destroys each service object in the execution_context set, and removes it from the set, in reverse order of addition to the set.

13.7.5 execution_context globals [async.exec.ctx.globals]

The functions use_service, make_service, and has_service do not introduce data races as a result of concurrent calls to those functions from different threads.

template<class Service> typename Service::key_type& use_service(execution_context& ctx);

Effects: If an object of type Service::key_type does not already exist in the execution_context set identified by ctx, creates an object of type Service, initialized as Service(ctx), and adds it to the set.

Returns: A reference to the corresponding service of ctx.

Remarks: The reference returned remains valid until a call to destroy.

template<class Service, class... Args> Service& make_service(execution_context& ctx, Args&&... args);

Requires: A service object of type Service::key_type does not already exist in the execution_context set identified by ctx.

Effects: Creates an object of type Service, initialized as Service(ctx, forward<Args>(args)...), and adds it to the execution_context set identified by ctx.

Throws: service_already_exists if a corresponding service object of type Service::key_type is already present in the set.

Remarks: The reference returned remains valid until a call to destroy.

template<class Service> bool has_service(const execution_context& ctx) noexcept;

Returns: true if an object of type Service::key_type is present in ctx, otherwise false.