Skip to content

SO 5.8 ByExample Coop User Resources

Yauheni Akhotnikau edited this page Jul 7, 2023 · 1 revision

Note. It is better to read SO-5.8 Basics and SO-5.8 By Example Cooperation Notifications before this text.

Sample details

This sample demonstrates how lifetime of object that is shared between several agents can be controlled by their cooperation.

An instance of class logger_t is created. This instance is placed under control of the parent cooperation. A reference to this instance is passed to object of class a_parent_t.

The agent a_parent_t creates a child cooperation and passes its reference to logger_t object to every agent in the child cooperation.

Every child agent sends a notification msg_child_finished to the a_parent_t. When a_parent_t receives notifications from all children agents it deregisters itself.

The most important parts of the sample are invocations of logger_t methods in the constructors and desctructors of a_parent_t and a_child_t. This invocations end successfully:

[log] -- logger created --
[log] parent created
[log] creating child cooperation...
[log] a_child_1: created
[log] a_child_2: created
[log] child cooperation created
[log] a_child_1: finishing
[log] a_child_2: finishing
[log] child_finished notification received
[log] child_finished notification received
[log] stopping so_environment...
[log] a_child_1: destroyed
[log] a_child_2: destroyed
[log] parent destroyed
[log] -- logger destroyed --

It is because lifetime of logger_t object is longer then lifetime of a_child_t and a_parent_t objects. This lifetime is guaranteed by SObjectizer: SObjectizer deletes agents from child cooperation, then the child cooperation object, then the agent from parent cooperation and only then -- objects which are under control of that cooperation.

This fact can be used if there is necessity of sharing dynamically allocated object between several agents (in same cooperation or in children cooperations).

Sample code

#include <iostream>
#include <stdexcept>
#include <string>

// Main SObjectizer header file.
#include <so_5/all.hpp>

// Logger sample class.
// Object of that class will be used as user resource for cooperation.
class logger_t
{
	public :
		logger_t()
		{
			std::cout << "[log] -- logger created --" << std::endl;
		}
		~logger_t()
		{
			std::cout << "[log] -- logger destroyed --" << std::endl;
		}

		void
		log( const std::string & what )
		{
			std::cout << "[log] " << what << std::endl;
		}
};

// A signal for parent cooperation about child work finish.
struct msg_child_finished final : public so_5::signal_t {};

// A class of child agent.
class a_child_t final :	public so_5::agent_t
{
	public :
		a_child_t(
			context_t ctx,
			std::string agent_name,
			so_5::mbox_t parent_mbox,
			logger_t & logger )
			:	so_5::agent_t( ctx )
			,	m_agent_name( std::move( agent_name ) )
			,	m_parent_mbox( std::move( parent_mbox ) )
			,	m_logger( logger )
		{
			m_logger.log( m_agent_name + ": created" );
		}
		~a_child_t() override
		{
			m_logger.log( m_agent_name + ": destroyed" );
		}

		void so_evt_start() override
		{
			m_logger.log( m_agent_name + ": finishing" );
			so_5::send< msg_child_finished >( m_parent_mbox );
		}

	private :
		const std::string m_agent_name;
		const so_5::mbox_t m_parent_mbox;
		logger_t & m_logger;
};

// A class of parent agent.
class a_parent_t final : public so_5::agent_t
{
	public :
		a_parent_t(
			context_t ctx,
			logger_t & logger,
			size_t child_count )
			:	so_5::agent_t( ctx )
			,	m_logger( logger )
			,	m_child_count( child_count )
			,	m_child_finished( 0 )
		{
			m_logger.log( "parent created" );
		}

		~a_parent_t() override
		{
			m_logger.log( "parent destroyed" );
		}

		void so_define_agent() override
		{
			so_default_state().event(
					&a_parent_t::evt_child_finished );
		}

		void so_evt_start() override
		{
			m_logger.log( "creating child cooperation..." );
			register_child_coop();
			m_logger.log( "child cooperation created" );
		}

		void evt_child_finished( mhood_t< msg_child_finished > )
		{
			m_logger.log( "child_finished notification received" );

			++m_child_finished;
			if( m_child_finished >= m_child_count )
			{
				m_logger.log( "stopping so_environment..." );
				so_deregister_agent_coop_normally();
			}
		}

	private :
		logger_t & m_logger;

		const size_t m_child_count;
		size_t m_child_finished;

		void register_child_coop()
		{
			so_5::introduce_child_coop( *this,
				[this]( so_5::coop_t & coop ) 
				{
					for( size_t i = 0; i != m_child_count; ++i )
						coop.make_agent< a_child_t >(
								"a_child_" + std::to_string(i+1),
								so_direct_mbox(), m_logger );
				} );
		}
};

// The SObjectizer Environment initialization.
void init( so_5::environment_t & env )
{
	env.introduce_coop( []( so_5::coop_t & coop ) {
		auto logger = coop.take_under_control( std::make_unique< logger_t >() );
		coop.make_agent< a_parent_t >( *logger, 2u );
	} );
}

int main()
{
	try
	{
		so_5::launch( &init );
	}
	catch( const std::exception & ex )
	{
		std::cerr << "Error: " << ex.what() << std::endl;
		return 1;
	}

	return 0;
}
Clone this wiki locally