Stiffstream / sobjectizer

An implementation of Actor, Publish-Subscribe, and CSP models in one rather small C++ framework. With performance, quality, and stability proved by years in the production.

Home Page:https://stiffstream.com/en/products/sobjectizer.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Should there be agent_t::so_disp_binder() and agent_t::so_coop_default_disp_binder() methods?

eao197 opened this issue · comments

Sometimes it's necessary to bind a child coop to the same dispatcher as the parent coop. Something like:

void parent_agent::evt_some_event(mhood_t<some_msg>) {
  // It's time to make a new child coop.
  so_5::introduce_child_coop( *this,
    // OOPS: I want to specify the same dispatcher as it used for `this` agent, but
    // how to get a disp_binder for it?
    ...);
}

The only solution available today is to pass disp_binder to the constructor of the parent_agent with storing it inside parent_agent:

class parent_agent final : public so_5::agent_t
{
  so_5::disp_binder_t m_this_binder;

  void evt_some_event(mhood_t<some_msg>) {
    // It's time to make a new coop.
    so_5::introduce_child_coop(*this,
      // Now we can specify m_this_binder as the binder for a new coop.
      m_this_binder,
      ...);
  }

public:
  parent_agent(context_t ctx,
    // Disp-binder has to be passed to the constructor.
    so_5::disp_binder_t this_binder)
    : so_5::agent_t{std::move(ctx)}
    , m_this_binder{std::move(this_binder)}
  {}
  ...
};

...
// Somewhere an instance of parent_agent is created.
auto binder = so_5::disp::active_obj::make_dispatcher(env).binder();
env.introduce_coop(binder, [&](so_5::coop_t & coop) {
  coop.make_agent<parent_agent>(binder);
  ...
});

Since v.5.7.5 the disp_binder for an agent is stored inside the agent. So it's possible to add a method like:

[[nodiscard]]
so_5::disp_binder_shptr_t
so_disp_binder() const; /* Open question: should/may it be noexcept? */

to the agent_t class. This addition will allow to write more simple code:

void parent_agent::evt_some_event(mhood_t<some_msg>) {
  // It's time to make a new child coop.
  so_5::introduce_child_coop( *this,
    // Just use the binder of `this` agent.
    so_disp_binder(),
    ...);
}

Moreover, sometimes parent_agent may use a different dispatcher. Something like that:

// The thread_pool dispatcher will be used as the default for a coop.
env.introduce_coop(so_5::disp::thread_pool::make_dispatcher(env, 8u).binder(),
  [&](so_5::coop_t & coop) {
    // But the parent_agent will use one_thread dispatcher.
    coop.make_agent_with_binder<parent_agent>(
      so_5::disp::one_thread::make_dispatcher(env).binder(),
      ...);

    // Other agents will be bound to the default thread_pool dispatcher.
    coop.make_agent<worker>(...);
    coop.make_agent<worker>(...);
    coop.make_agent<worker>(...);
  })

If the parent_agent wants to bind a child coop to the same dispatcher as the parent's coop, then it seems to be possible to provide a so_coop_default_disp_binder() method to the agent_t class:

[[nodiscard]]
so_5::disp_binder_shptr_t
so_coop_default_disp_binder() const; /* NOTE: it's not noexcept and may throw! */

This method will allow to write something like that:

void parent_agent::evt_some_event(mhood_t<some_msg>) {
  // It's time to make a new child coop.
  so_5::introduce_child_coop( *this,
    // Just use the binder of the coop of `this` agent.
    so_coop_default_disp_binder(),
    ...);
}

PS. It would be great if someone can provide a feedback related to such a feature. It's it really needed and would be useful for someone?

This issue is related to #14

Implemented in v.5.8.1.