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

`so_evt_finish` not called until `so_evt_start` is running?

ilpropheta opened this issue · comments

Hi,
quick one: can you confirm that so_evt_finish won't be called until so_evt_start returns?

Imagine this scenario:

struct some_agent : so_5::agent_t
{
	some_agent(so_5::agent_context_t ctx)
		: agent_t(std::move(ctx)), m_stop(m_source.get_token())
	{
	}

	void so_evt_start() override
	{
		while (!m_stop.stop_requested())
		{
			// do work
		}
	}

	void so_evt_finish() override
	{
		m_source.request_stop();
	}

private:
	so_5::mbox_t m_commands;
	std::stop_source m_source;
	std::stop_token m_stop;	
};

int main()
{
	std::stop_token st = ... // bound somehow to CTRL+C
	
	const so_5::wrapped_env_t env;	
	env.environment().introduce_coop([](so_5::coop_t& c) {
		c.make_agent_with_binder<some_agent>(so_5::disp::active_obj::make_dispatcher(env.environment()).binder());
		// ... other agents		
	});
	
	wait_for_termination(st); // wait until CTRL+C is pressed
}

I expect that some_agent hangs forever. One solution is to inject the stop_token into the constructor and to request stop from outside. For example:

struct some_agent : so_5::agent_t
{
	some_agent(so_5::agent_context_t ctx, std::stop_token st)
		: agent_t(std::move(ctx)), m_stop(std::move(st))
	{
	}

	void so_evt_start() override
	{
		while (!m_stop.stop_requested())
		{
			// do work
		}
	}

private:
	so_5::mbox_t m_commands;
	std::stop_token m_stop;
};

// initialization
        ...
	c.make_agent_with_binder<some_agent>(so_5::disp::active_obj::make_dispatcher(env.environment()).binder(), st);

Does it make sense? I know that a thread would be a better fit (std::jthread in particular) than using agent_t here. However, this way my design stays consistent, the dispatching policy is configured as usual, and everything is managed by the environment.
So this has some advantages.
Which are your thoughts? Is that an acceptable design?

Many thanks!

commented

Hi!

can you confirm that so_evt_finish won't be called until so_evt_start returns?

Yes. so_evt_start and so_evt_finish are called as the result of processing special hidden events evt_start and evt_finish that are sent to the agent the usual way. So, evt_finish can't be extracted from agent's queue until so_evt_start returns.

Does it make sense?
Is that an acceptable design?

Yes, sometimes I use something like that (but without std::stop_token, because we haven't switched to C++20 yet).

Thanks @eao197!