SObjectizer  5.8
Loading...
Searching...
No Matches
so_5/ping_pong_with_owner/main.cpp
#include <iostream>
#include <string>
// Main SObjectizer header file.
#include <so_5/all.hpp>
// Ping signal.
// Signal is a special type of message which has no actual data.
// Sending of signals is like sending only atoms in Erlang.
struct ping final : public so_5::signal_t {};
// Pong signal.
struct pong final : public so_5::signal_t {};
// Message with result of pinger/ponger run.
// Unlike signal message it must have actual data.
struct run_result
{
std::string m_result;
};
// Pinger agent.
class pinger final : public so_5::agent_t
{
public :
pinger(
// Working context for agent.
context_t ctx,
// Parent's mbox for result sending.
so_5::mbox_t parent )
: so_5::agent_t( ctx )
, m_parent( std::move(parent) )
{}
// Ponger mbox will be available only after
// creation of pinger/ponger pair.
void set_ponger_mbox( const so_5::mbox_t & mbox ) {
m_ponger = mbox;
}
// This method is automatically called by SObjectizer
// during agent's registration procedure.
void so_define_agent() override {
// Subscription for only one signal.
[this](mhood_t< pong >) {
++m_pongs;
so_5::send< ping >( m_ponger );
} );
}
// This method is automatically called by SObjectizer
// just after successful registration.
// Pinger uses this method to initiate message exchange.
void so_evt_start() override {
// Sending signal by corresponding function.
so_5::send< ping >( m_ponger );
}
// This method is automatically called by SObjectizer
// just after successful agent's deregistration.
void so_evt_finish() override {
// Sending result message by corresponding function.
// Receiver of the message.
m_parent,
// This string will be forwarded to run_result's constructor.
"pongs: " + std::to_string( m_pongs ) );
}
private :
const so_5::mbox_t m_parent;
so_5::mbox_t m_ponger;
unsigned int m_pongs = 0;
};
// Ponger agent is very similar to pinger.
// But it hasn't so_evt_start method because it will
// wait the first ping signal from the pinger.
class ponger final : public so_5::agent_t
{
public :
ponger( context_t ctx, so_5::mbox_t parent )
: so_5::agent_t( ctx )
, m_parent( std::move(parent) )
{}
void set_pinger_mbox( const so_5::mbox_t & mbox ) {
m_pinger = mbox;
}
void so_define_agent() override {
[this](mhood_t< ping >) {
++m_pings;
so_5::send< pong >( m_pinger );
} );
}
void so_evt_finish() override {
m_parent,
"pings: " + std::to_string( m_pings ) );
}
private :
const so_5::mbox_t m_parent;
so_5::mbox_t m_pinger;
unsigned int m_pings = 0;
};
// Parent agent.
// Creates pair of pinger/ponger agents, then limits their working time,
// then handles their run results.
class parent final : public so_5::agent_t
{
public :
parent( context_t ctx ) : so_5::agent_t( ctx )
{}
void so_define_agent() override {
// Arriving of time limit signal means that
// child cooperation must be deregistered.
so_default_state().event( [this](mhood_t< stop >) {
// Cooperation name for deregistration.
m_child,
// The reason of deregistration.
// This value means that deregistration is caused
// by application logic.
} );
// NOTE: message type is automatically deduced from
// event handlers signatures.
// The first result will be received in default state.
so_default_state().event( &parent::evt_first_result );
// But the second one will be received in the next state.
st_first_result_got.event( &parent::evt_second_result );
}
void so_evt_start() override {
// Creation of child cooperation with pinger and ponger.
// Parent of the new cooperation.
*this,
// Child cooperation will use active_obj dispatcher.
// So pinger and ponger will work on the different
// working threads.
// active_obj dispatcher will be used as a primary
// dispatcher for that cooperation.
so_environment() ).binder() );
// Filling the child cooperation.
auto a_pinger = coop->make_agent< pinger >( so_direct_mbox() );
auto a_ponger = coop->make_agent< ponger >( so_direct_mbox() );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
// Registration of the child coop.
m_child = so_environment().register_coop( std::move(coop) );
// Limit the pinger/ponger exchange time.
*this, std::chrono::seconds( 1 ) );
}
private :
// Time limit signal.
struct stop : public so_5::signal_t {};
// Additional state for the agent.
// This state means that the first result from children agents
// has been received and that the parent expects the last one.
const state_t st_first_result_got{ this };
// Result's accumulator.
std::string m_results;
// Handle of child coop.
// Will receive actual value when child will be registered.
// Event handler for the first result.
void evt_first_result( const run_result & evt ) {
m_results = evt.m_result + "; ";
// Agent's state must be changed.
this >>= st_first_result_got;
}
// Event handler for the next (and last) result.
void evt_second_result( const run_result & evt ) {
m_results += evt.m_result;
// Show the results and finish work.
std::cout << m_results << std::endl;
// This is deregistration of the last live cooperation.
// SO Environment will finish its work.
}
};
int main()
{
try
{
// Create SO Environment objects and run SO Run-Time inside it.
// SO Environment initialization routine.
[]( so_5::environment_t & env )
{
// We must have the cooperation with just one
// agent inside it.
// The single agent in the cooperation.
env.make_agent< parent >() );
} );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
A helper header file for including all public SObjectizer stuff.
A base class for agents.
Definition agent.hpp:673
virtual void so_define_agent()
Hook on define agent for SObjectizer.
Definition agent.cpp:975
void so_deregister_agent_coop_normally()
A helper method for deregistering agent's coop in case of normal deregistration.
Definition agent.cpp:1116
virtual void so_evt_finish()
Hook of agent finish in SObjectizer.
Definition agent.cpp:838
const mbox_t & so_direct_mbox() const
Get the agent's direct mbox.
Definition agent.cpp:887
environment_t & so_environment() const noexcept
Access to the SObjectizer Environment which this agent is belong.
Definition agent.cpp:987
const state_t & so_default_state() const
Access to the agent's default state.
Definition agent.cpp:900
virtual void so_evt_start()
Hook on agent start inside SObjectizer.
Definition agent.cpp:832
Type of smart handle for a cooperation.
SObjectizer Environment.
coop_handle_t register_agent_as_coop(std::unique_ptr< A > agent)
Register single agent as a cooperation.
std::unique_ptr< Agent > make_agent(Args &&... args)
Helper method for simplification of agents creation.
coop_handle_t register_coop(coop_unique_holder_t agent_coop)
Register a cooperation.
void deregister_coop(coop_handle_t coop, int reason) noexcept
Deregister the cooperation.
A base class for agent signals.
Definition message.hpp:275
const state_t & event(Args &&... args) const
Helper for subscription of event handler in this state.
Definition agent.hpp:3925
const int normal
Normal deregistration.
Definition coop.hpp:46
SO_5_FUNC dispatcher_handle_t make_dispatcher(environment_t &env, const std::string_view data_sources_name_base, disp_params_t params)
Create an instance of active_obj dispatcher.
Private part of message limit implementation.
Definition agent.cpp:33
void launch(Init_Routine &&init_routine)
Launch a SObjectizer Environment with default parameters.
Definition api.hpp:142
void send(Target &&to, Args &&... args)
A utility function for creating and delivering a message or a signal.
coop_unique_holder_t create_child_coop(agent_t &owner, Args &&... args)
A simple way for creating child cooperation.
void send_delayed(Target &&target, std::chrono::steady_clock::duration pause, Args &&... args)
A utility function for creating and delivering a delayed message to the specified destination.
STL namespace.