dive into sobjectizer 5.5. introductory part

194
Dive into SObjectizer-5.5 SObjectizer Team, Feb 2015 Introductory part

Upload: yauheni-akhotnikau

Post on 16-Aug-2015

107 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Dive into SObjectizer 5.5. Introductory part

Dive into SObjectizer-5.5

SObjectizer Team, Feb 2015

Introductory part

Page 2: Dive into SObjectizer 5.5. Introductory part

SObjectizer is a small tool that simplifies thedevelopment of concurrent and event-driven applications in C++.

SObjectizer Team, Feb 2015

Page 3: Dive into SObjectizer 5.5. Introductory part

SObjectizer is a small tool that simplifies thedevelopment of concurrent and event-driven applications in C++.

SObjectizer Team, Feb 2015

SObjectizer was designed under the influence of several approaches. The Actor Model* is one of them. But the history of SObjectizer started long

before this model became widely known.

* http://en.wikipedia.org/wiki/Actor_model

Page 4: Dive into SObjectizer 5.5. Introductory part

SObjectizer’s main ideas and principles were formulated in the middle of 1990s, during the development of SCADA Objectizer project in Development Bureau of System Programming in Homyel, Belarus (1996-2000).

SObjectizer Team, Feb 2015

Page 5: Dive into SObjectizer 5.5. Introductory part

SObjectizer’s main ideas and principles were formulated in the middle of 1990s, during the development of SCADA Objectizer project in Development Bureau of System Programming in Homyel, Belarus (1996-2000).

SObjectizer Team, Feb 2015

SCADA Objectizer’s ideas were reused in the new project SObjectizer-4 in 2002.

Page 6: Dive into SObjectizer 5.5. Introductory part

SObjectizer’s main ideas and principles were formulated in the middle of 1990s, during the development of SCADA Objectizer project in Development Bureau of System Programming in Homyel, Belarus (1996-2000).

SObjectizer Team, Feb 2015

SCADA Objectizer’s ideas were reused in the new project SObjectizer-4 in 2002.

Evolution of SObjectizer-4 was stopped in 2010 and the development of SObjectizer-5 started.

Page 7: Dive into SObjectizer 5.5. Introductory part

SObjectizer was an in-house project ofJSC Intervale* for the long time.

SObjectizer Team, Feb 2015*www.intervale.ru

Page 8: Dive into SObjectizer 5.5. Introductory part

SObjectizer was an in-house project ofJSC Intervale* for the long time.

SObjectizer was used in the development of the following software systems:

SObjectizer Team, Feb 2015*www.intervale.ru

Page 9: Dive into SObjectizer 5.5. Introductory part

SObjectizer was an in-house project ofJSC Intervale* for the long time.

SObjectizer was used in the development of thefollowing software systems:● SMS/USSD traffic service

SObjectizer Team, Feb 2015*www.intervale.ru

Page 10: Dive into SObjectizer 5.5. Introductory part

SObjectizer was an in-house project ofJSC Intervale* for the long time.

SObjectizer was used in the development of thefollowing software systems:● SMS/USSD traffic service● financial transaction handling

SObjectizer Team, Feb 2015*www.intervale.ru

Page 11: Dive into SObjectizer 5.5. Introductory part

SObjectizer was an in-house project ofJSC Intervale* for the long time.

SObjectizer was used in the development of thefollowing software systems:● SMS/USSD traffic service● financial transaction handling● software parameters monitoring.

SObjectizer Team, Feb 2015*www.intervale.ru

Page 12: Dive into SObjectizer 5.5. Introductory part

SObjectizer was published as an OpenSource project on SourceForge under 3-clauses BSD-licence in 2006.

SObjectizer Team, Feb 2015

Page 13: Dive into SObjectizer 5.5. Introductory part

SObjectizer was published as an OpenSourceproject on SourceForge under 3-clausesBSD-licence in 2006.

Since 2013 SObjectizer’s development completely moved to SourceForge.

SObjectizer Team, Feb 2015

Page 14: Dive into SObjectizer 5.5. Introductory part

SObjectizer was published as an OpenSourceproject on SourceForge under 3-clausesBSD-licence in 2006.

Since 2013 SObjectizer’s development completelymoved to SourceForge.

SObjectizer now is an independent project which is totally separated from JSC Intervale.

SObjectizer Team, Feb 2015

Page 15: Dive into SObjectizer 5.5. Introductory part

SObjectizer allows to build a concurrent application as a set of agent-objects...

SObjectizer Team, Feb 2015

Page 16: Dive into SObjectizer 5.5. Introductory part

SObjectizer allows to build a concurrent application as a set of agent-objects...

...which interact with each other only by means of asynchronous messages.

SObjectizer Team, Feb 2015

Page 17: Dive into SObjectizer 5.5. Introductory part

Every agent receives its own working context. This context is used for message processing.

SObjectizer Team, Feb 2015

Page 18: Dive into SObjectizer 5.5. Introductory part

Every agent receives its own working context.This context is used for message processing.

An agent is bound to its context. It allows not to worry about defense of integrity of the agent’s data in the multithreaded environment.

SObjectizer Team, Feb 2015

Page 19: Dive into SObjectizer 5.5. Introductory part

Every agent receives its own working context.This context is used for message processing.

An agent is bound to its context. It allows not toworry about defense of integrity of the agent’sdata in the multithreaded environment.

This defense is automatically performed by SObjectizer itself!

SObjectizer Team, Feb 2015

Page 21: Dive into SObjectizer 5.5. Introductory part

All SObjectizer’s work is performed inside SObjectizer Environment.

SObjectizer Team, Feb 2015

Page 22: Dive into SObjectizer 5.5. Introductory part

All SObjectizer’s work is performed insideSObjectizer Environment.

SObjectizer Environment is a container for SObjectizer Run-Time, agent’s cooperations, message boxes, dispatchers and timer thread.

SObjectizer Team, Feb 2015

Page 23: Dive into SObjectizer 5.5. Introductory part

All SObjectizer’s work is performed insideSObjectizer Environment.

SObjectizer Environment is a container forSObjectizer Run-Time, agent’s cooperations,message boxes, dispatchers and timer thread.

It is possible to create several Environments in one application. Each Environment will work

independently from others.

SObjectizer Team, Feb 2015

Page 24: Dive into SObjectizer 5.5. Introductory part

SObjectizer Environment is created byso_5::launch() function.

SObjectizer Team, Feb 2015

Page 25: Dive into SObjectizer 5.5. Introductory part

SObjectizer Environment is created byso_5::launch() function.

A new instance of Environment is created and started inside so_5::launch(). The control from so_5::launch() is returned only when Environment finished its execution.

SObjectizer Team, Feb 2015

Page 26: Dive into SObjectizer 5.5. Introductory part

SObjectizer Environment is created byso_5::launch() function.

A new instance of Environment is created andstarted inside so_5::launch(). The control fromso_5::launch() is returned only when Environmentfinished its execution.

What happened inside Environment is completely dependent on user supplied starting function.

SObjectizer Team, Feb 2015

Page 27: Dive into SObjectizer 5.5. Introductory part

SObjectizer Environment is created byso_5::launch() function.

A new instance of Environment is created andstarted inside so_5::launch(). The control fromso_5::launch() is returned only when Environmentfinished its execution.

What happened inside Environment is completely dependent on user supplied starting function.

so_5::launch() throws in the case of an error.

SObjectizer Team, Feb 2015

Page 28: Dive into SObjectizer 5.5. Introductory part

It looks like that:#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

SObjectizer Team, Feb 2015

Page 29: Dive into SObjectizer 5.5. Introductory part

#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

Main header file with all necessary definitions.

It looks like that:

SObjectizer Team, Feb 2015

Page 30: Dive into SObjectizer 5.5. Introductory part

#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

User supplied starting function.It creates all application specific stuff.

It looks like that:

SObjectizer Team, Feb 2015

Page 31: Dive into SObjectizer 5.5. Introductory part

#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

SObjectizer Environment object. Starting function will work inside it.

It looks like that:

SObjectizer Team, Feb 2015

Page 32: Dive into SObjectizer 5.5. Introductory part

#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

Creation of Environment, starting it and invoking init() inside that Environment.Control will be returned when all application-specific agents finish their work.

It looks like that:

SObjectizer Team, Feb 2015

Page 33: Dive into SObjectizer 5.5. Introductory part

#include <iostream>

#include <so_5/all.hpp>

void init( so_5::rt::environment_t & env ) { ... }

int main(){ try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

Error handling. Error reporting is done via exceptions.

It looks like that:

SObjectizer Team, Feb 2015

Page 34: Dive into SObjectizer 5.5. Introductory part

Usually one or more agent’s cooperations are created inside the starting function.

SObjectizer Team, Feb 2015

Page 35: Dive into SObjectizer 5.5. Introductory part

Usually one or more agent’s cooperations are createdinside the starting function.

Cooperation is a group of agents which must work together and can’t exist one without another.

SObjectizer Team, Feb 2015

Page 36: Dive into SObjectizer 5.5. Introductory part

Usually one or more agent’s cooperations are createdinside the starting function.

Cooperation is a group of agents which must work together and can’t exist one without another.

For example: pinger and ponger agents which send ping/pong messages back and forth.

SObjectizer Team, Feb 2015

Page 37: Dive into SObjectizer 5.5. Introductory part

Usually one or more agent’s cooperations are createdinside the starting function.

Cooperation is a group of agents which must worktogether and can’t exist one without another.

For example: pinger and ponger agents whichsend ping/pong messages back and forth.

There is no any sense in pinger agent without ponger agent. They must appear and disappear at the same time.

SObjectizer Team, Feb 2015

Page 38: Dive into SObjectizer 5.5. Introductory part

One or more agent’s cooperations are createdinside the starting function usually.

Cooperation is a group of agents which must worktogether and can’t exist one without another.

For example: pinger and ponger agents whichsend ping/pong messages back and forth.

There is no any sense in pinger agent withoutponger agent. They must appear and disappear atthe same time.

And cooperation is used for that!SObjectizer Team, Feb 2015

Page 39: Dive into SObjectizer 5.5. Introductory part

Creation of a cooperation with two agents:

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

SObjectizer Team, Feb 2015

Page 40: Dive into SObjectizer 5.5. Introductory part

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

Creation consists of three steps.

At the beginning the Environment creates a cooperation...

SObjectizer Team, Feb 2015

Creation of a cooperation with two agents:

Page 41: Dive into SObjectizer 5.5. Introductory part

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

Then the cooperation is filled up with agents...

SObjectizer Team, Feb 2015

Creation of a cooperation with two agents:

Page 42: Dive into SObjectizer 5.5. Introductory part

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

Then the cooperation is being registered.

SObjectizer Team, Feb 2015

Creation of a cooperation with two agents:

Page 43: Dive into SObjectizer 5.5. Introductory part

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

Every cooperation must have unique name. The uniqueness is checked inside register_coop().

But SObjectizer can be asked to generate the name for the new cooperation automaticly.

SObjectizer Team, Feb 2015

Creation of a cooperation with two agents:

Page 44: Dive into SObjectizer 5.5. Introductory part

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) );

env.register_coop( std::move( coop ) );}

Starting function finishes after cooperation registration.

But the Environment will work until that cooperation will be deregistered.Or the Environment stop function will be called explicitly.

SObjectizer Team, Feb 2015

Creation of a cooperation with two agents:

Page 46: Dive into SObjectizer 5.5. Introductory part

What is an agent?

Let’s start with the simplest agent in this example.

A ponger agent.

SObjectizer Team, Feb 2015

Page 47: Dive into SObjectizer 5.5. Introductory part

What is an agent?

Let’s start with the simplest agent in this example.

A ponger agent.

It does very simple tasks:● receives ping messages● replies with pong messages.

SObjectizer Team, Feb 2015

Page 48: Dive into SObjectizer 5.5. Introductory part

What is an agent?

Let’s start with the simplest agent in this example.

A ponger agent.

It does very simple tasks:● receives ping messages● replies with pong messages.

So first of all let’s define those messages...

SObjectizer Team, Feb 2015

Page 49: Dive into SObjectizer 5.5. Introductory part

Definition of the messages:struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

SObjectizer Team, Feb 2015

Page 50: Dive into SObjectizer 5.5. Introductory part

struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

Every message must be represented by a separate C++ class (or a structure).

Message dispatching and selection of a handler are based on the message type information.

SObjectizer Team, Feb 2015

Definition of the messages:

Page 51: Dive into SObjectizer 5.5. Introductory part

struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

All messages types with some data inside must be derived from common base class so_5::rt::message_t.

There are also messages without actual data. They are called signals. They will be described further.

SObjectizer Team, Feb 2015

Definition of the messages:

Page 52: Dive into SObjectizer 5.5. Introductory part

struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

SObjectizer has no significant limits for message’s content.

In this particular case the m_req and m_resp fields are necessary for the sample logic. They have no relation to SObjectizer features.

SObjectizer Team, Feb 2015

Definition of the messages:

Page 53: Dive into SObjectizer 5.5. Introductory part

ponger agent:

SObjectizer Team, Feb 2015

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Page 54: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Every ordinary agent must be represented by a C++ class.

There also can be non ordinary agents named ad-hoc agents. They will be described further.

SObjectizer Team, Feb 2015

ponger agent:

Page 55: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Class of ordinary agent must be derived from common base type so_5::rt::agent_t.

SObjectizer Team, Feb 2015

ponger agent:

Page 56: Dive into SObjectizer 5.5. Introductory part

ponger agent:class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Every agent must be bound to an Environment where an agent will work.

Because of that a reference to Environment object must be passed to the agent’s constructor and redirected to the constructor of the base type so_5::rt::agent_t.

SObjectizer Team, Feb 2015

Page 57: Dive into SObjectizer 5.5. Introductory part

ponger agent:class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

SObjectizer calls so_define_agent() method before an agent will be registered.

Agent must perform all necessary tuning actions in this method. Create message subscriptions in particular.

SObjectizer Team, Feb 2015

Page 58: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Ponger agent subscribes only to one message of ping type. This message is going from a message box with name “table”.

Message box must be specified explicitly. But the message type is deduced by SObjectizer automatically from the message handler signature.

SObjectizer Team, Feb 2015

ponger agent:

Page 59: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

A message handler method is named event handler method. Or just event.

SObjectizer Team, Feb 2015

ponger agent:

Page 60: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

A message instance which caused an event is passed to event handler by const reference.Event handler must not modify that message instance because it can be handled by the different agents at the same time.

SObjectizer Team, Feb 2015

ponger agent:

Page 61: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Agent replies by sending a pong message instance to the message box with name “table”.

SObjectizer Team, Feb 2015

ponger agent:

Page 62: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

so_5::send() template function constructs an object of pong type and sends it to the message box specified.

SObjectizer Team, Feb 2015

ponger agent:

Page 63: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

All arguments after message box are passed to the message object’s constructor.In this case it is resp argument for the pong’s constructor.

SObjectizer Team, Feb 2015

ponger agent:

Page 64: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); }

private : const so_5::rt::mbox_t m_table;

void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); }};

Ponger agent gets a reference to the message box for message exchange by itself.In this case it is a message box with name “table”. This box is created by invocation of create_local_mbox(). A reference to message box is stored inside the agent.

SObjectizer Team, Feb 2015

ponger agent:

Page 65: Dive into SObjectizer 5.5. Introductory part

pinger agent (beginning):class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); }

virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); }

SObjectizer Team, Feb 2015

Page 66: Dive into SObjectizer 5.5. Introductory part

class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); }

virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); }

Pinger agent is very similar to the ponger agent: receives a reference to an Environment in its constructor and creates a reference to message box with name “table”. Pinger also subscribes to a single message in so_define_agent().

SObjectizer Team, Feb 2015

pinger agent (beginning):

Page 67: Dive into SObjectizer 5.5. Introductory part

class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); }

virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); }

But there is one significant distinction: so_evt_start() method. This method is called just after successful registration of the agent’s cooperation. An agent can perform any starting actions in that method.

In this particular case: sends the very first ping message.

SObjectizer Team, Feb 2015

pinger agent (beginning):

Page 68: Dive into SObjectizer 5.5. Introductory part

pinger agent (ending):private : const so_5::rt::mbox_t m_table;

void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); }};

SObjectizer Team, Feb 2015

Page 69: Dive into SObjectizer 5.5. Introductory part

pinger agent (ending):private : const so_5::rt::mbox_t m_table;

void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); }};

In the evt_pong() the agent can continue the message exchange by sending the next ping message. Or, in the case when all messages have been sent, cooperation deregistration can be initiated.

SObjectizer Team, Feb 2015

Page 70: Dive into SObjectizer 5.5. Introductory part

pinger agent (ending):private : const so_5::rt::mbox_t m_table;

void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); }};

The reasons for deregistering a cooperation might be different. In this case the deregistration is a normal part of the application logic.

There will be no live cooperations after deregistration of pinger/ponger cooperation. So Environment will finish its work and so_5::launch will return control to the caller.

SObjectizer Team, Feb 2015

Page 71: Dive into SObjectizer 5.5. Introductory part

Few words about message boxes (mboxes)...

SObjectizer Team, Feb 2015

Page 72: Dive into SObjectizer 5.5. Introductory part

Few words about message boxes (mboxes)...

Despite other similar tools like Erlang, Akka or CAF, in SObjectizer a message is sent not to an agent, but to a message box (mbox).

SObjectizer Team, Feb 2015

Page 73: Dive into SObjectizer 5.5. Introductory part

Few words about message boxes (mboxes)...

Despite other similar tools like Erlang, Akka orCAF, in SObjectizer a message is sent not to anagent, but to a message box (mbox).

There could be one agent behind the mbox.Or many agents.

Or none.

SObjectizer Team, Feb 2015

Page 74: Dive into SObjectizer 5.5. Introductory part

There are two types of mboxes in SObjectizer:

SObjectizer Team, Feb 2015

Page 75: Dive into SObjectizer 5.5. Introductory part

There is two types of mboxes in SObjectizer:

Multi-Producers/Multi-Consumers mboxes.They are like “bulletin boards”. A message sent to such mbox becomes available for all subscribers of the mbox. MPMC-mbox is shown in the code above.

SObjectizer Team, Feb 2015

Page 76: Dive into SObjectizer 5.5. Introductory part

There are two types of mboxes in SObjectizer:

Multi-Producers/Multi-Consumers mboxes.They are like “bulletin boards”. A message sent tosuch mbox becomes available for all subscribersof the mbox. MPMC-mbox is shown in the codeabove.

Multi-Producers/Single-Consumer mboxes.Mboxes of that type have only one subscriber. It is an agent who owns such mbox.

SObjectizer Team, Feb 2015

Page 77: Dive into SObjectizer 5.5. Introductory part

Lets add another agent to the example to show specifics of MPMC-mboxes...

SObjectizer Team, Feb 2015

Page 78: Dive into SObjectizer 5.5. Introductory part

Lets add another agent to the example to showspecifics of MPMC-mboxes…

This agent will listen the message exchange between pinger and ponger agents, and will count the messages sent.

SObjectizer Team, Feb 2015

Page 79: Dive into SObjectizer 5.5. Introductory part

listener agent:class listener : public so_5::rt::agent_t{public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); }

virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; }

private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0;};

SObjectizer Team, Feb 2015

Page 80: Dive into SObjectizer 5.5. Introductory part

listener agent:class listener : public so_5::rt::agent_t{public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); }

virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; }

private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0;};

It is necessary to receive two messages. Because of that the agent subscribes two events.Lambda-functions are used instead of event handler methods. Types of messages are automatically deduced from lambdas signatures.

SObjectizer Team, Feb 2015

Page 81: Dive into SObjectizer 5.5. Introductory part

listener agent:class listener : public so_5::rt::agent_t{public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {}

virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); }

virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; }

private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0;};

so_evt_finish() method is the opposite to so_evt_start(). It is called for agent just before the very end of agent’s work. In this case that method is used for result printing.

SObjectizer Team, Feb 2015

Page 82: Dive into SObjectizer 5.5. Introductory part

If we add a listener to the cooperation:

SObjectizer Team, Feb 2015

Page 83: Dive into SObjectizer 5.5. Introductory part

If we add a listener to the cooperation:

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) );

env.register_coop( std::move( coop ) );}

SObjectizer Team, Feb 2015

Page 84: Dive into SObjectizer 5.5. Introductory part

If we add a listener to the cooperation:

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) );

env.register_coop( std::move( coop ) );}

Then we will see at the end:result: 501/501

SObjectizer Team, Feb 2015

Page 85: Dive into SObjectizer 5.5. Introductory part

If we add a listener to the cooperation:

void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) );

env.register_coop( std::move( coop ) );}

Then we will see at the end:result: 501/501

It means that message sending to MPMC-mbox is a broadcast message sending.

SObjectizer Team, Feb 2015

Page 86: Dive into SObjectizer 5.5. Introductory part

MPMC-mboxes must be created manually. MPSC-mboxes, in contradiction, are created automatically for every agent.It means that every agent has its own MPSC-mbox named direct_mbox.

SObjectizer Team, Feb 2015

Page 87: Dive into SObjectizer 5.5. Introductory part

MPMC-mboxes must be created manually. MPSC-mboxes, in contradiction, are createdautomatically for every agent.It means that every agent has its ownMPSC-mbox named direct_mbox.

When a message is sent to MPSC-mbox it will go to mbox owner for processing. Or just discarded if mbox owner is not subscribed to that message.

SObjectizer Team, Feb 2015

Page 88: Dive into SObjectizer 5.5. Introductory part

MPMC-mboxes must be created manually.MPSC-mboxes, in contradiction, are createdautomatically for every agent.It means that every agent has its ownMPSC-mbox named direct_mbox.

When a message is sent to MPSC-mbox it will goto mbox owner for processing. Or just discarded ifmbox owner is not subscribed to that message.

It means that if two agents interact via direct_mboxes nobody can listen them.

SObjectizer Team, Feb 2015

Page 89: Dive into SObjectizer 5.5. Introductory part

But direct_mboxes are used not for creation of a “private channels” for message exchanges.

SObjectizer Team, Feb 2015

Page 90: Dive into SObjectizer 5.5. Introductory part

But direct_mboxes are used not for creation of a “private channels” for message exchanges.

Direct_mboxes are more efficient than MPMC-mboxes. Dispatching for direct_mboxes is simpler and requires fewer internal locks.

SObjectizer Team, Feb 2015

Page 91: Dive into SObjectizer 5.5. Introductory part

But direct_mboxes are used not for creation of a “private channels” for message exchanges.

Direct_mboxes are more efficient thanMPMC-mboxes. Dispatching for direct_mboxes issimpler and requires fewer internal locks.

Therefore usage of direct_mboxes is more preferable if application logic doesn’t require

broadcast message sending.

SObjectizer Team, Feb 2015

Page 92: Dive into SObjectizer 5.5. Introductory part

There is no need in broadcast message sending in the example above.

SObjectizer Team, Feb 2015

Page 93: Dive into SObjectizer 5.5. Introductory part

There is no need in broadcast message sendingin the example above.

Lets rewrite it with direct_mboxes.

SObjectizer Team, Feb 2015

Page 94: Dive into SObjectizer 5.5. Introductory part

There is no need in broadcast message sendingin the example above.

Lets rewrite it with direct_mboxes.

And throw out a listener agent. Lets pinger and ponger agent count the messages by themselves.

SObjectizer Team, Feb 2015

Page 95: Dive into SObjectizer 5.5. Introductory part

There is no need in broadcast message sendingin the example above.

Lets rewrite it with direct_mboxes.

And throw out a listener agent. Lets pinger andponger agent count the messages by themselves.

And replace messages with signals.

SObjectizer Team, Feb 2015

Page 96: Dive into SObjectizer 5.5. Introductory part

A signal is a special case of a message when only the fact of the message existence is important.

But the message itself has no any data inside.

SObjectizer Team, Feb 2015

Page 97: Dive into SObjectizer 5.5. Introductory part

A signal is a special case of a message whenonly the fact of the message existence isimportant.

But the message itself has no any data inside.

It is like sending of atoms in Erlang,when only an atom is sent

without any additional data.

SObjectizer Team, Feb 2015

Page 98: Dive into SObjectizer 5.5. Introductory part

In the application code written with SObjectizer signals are so widely used that SObjectizer’s API was extended to simplify usage of signals.

SObjectizer Team, Feb 2015

Page 99: Dive into SObjectizer 5.5. Introductory part

In the application code written with SObjectizersignals are so widely used that SObjectizer’s APIwas extended to simplify usage of signals.

At the API level the work with signal is very similar to the work with messages.

Sometimes.Sometimes not.

SObjectizer Team, Feb 2015

Page 100: Dive into SObjectizer 5.5. Introductory part

Replace ping and pong messages with signals...

SObjectizer Team, Feb 2015

Page 101: Dive into SObjectizer 5.5. Introductory part

Replace ping and pong messages with signals...

SObjectizer Team, Feb 2015

struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

struct ping : public so_5::rt::signal_t {};

struct pong : public so_5::rt::signal_t {};

Page 102: Dive into SObjectizer 5.5. Introductory part

Replace ping and pong messages with signals...

SObjectizer Team, Feb 2015

struct ping : public so_5::rt::message_t{ unsigned int m_req;

ping( unsigned int req ) : m_req{ req } {}};

struct pong : public so_5::rt::message_t{ unsigned int m_resp;

pong( unsigned int resp ) : m_resp{ resp } {}};

struct ping : public so_5::rt::signal_t {};

struct pong : public so_5::rt::signal_t {};

Signal types must be derived from so_5::rt::signal_t and must not contain any data inside.

Page 103: Dive into SObjectizer 5.5. Introductory part

Changing of pinger agent (beginning):

SObjectizer Team, Feb 2015

Page 104: Dive into SObjectizer 5.5. Introductory part

Changes to pinger agent (beginning):class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; }

virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }

SObjectizer Team, Feb 2015

Page 105: Dive into SObjectizer 5.5. Introductory part

Changes to pinger agent (beginning):class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; }

virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }

A direct_mbox can be accessed only after the agent creation. Because of that a separate method is needed for connecting of pinger and ponger agents. It will be called after instantiation of the agent.

SObjectizer Team, Feb 2015

Page 106: Dive into SObjectizer 5.5. Introductory part

Changing of pinger agent (beginning):class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; }

virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }

Only one argument is passed to event() method: this is lambda with event handling code. In this case event() creates subscription for a signal from direct_mbox of the agent.

SObjectizer Team, Feb 2015

Page 107: Dive into SObjectizer 5.5. Introductory part

Changing of pinger agent (beginning):class pinger : public so_5::rt::agent_t{public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; }

virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }

The signal type must be explicitly specified during subscription. A method or lambda-function without argument can only be used as signal handler. Unlike a message there is no a signal instance to be passed to a handler. Because of that there is no way to deduce signal type by the event handler’s signature.

SObjectizer Team, Feb 2015

Page 108: Dive into SObjectizer 5.5. Introductory part

Changing of pinger agent (ending): virtual void so_evt_start() override { so_5::send< ping >( m_ponger ); }

virtual void so_evt_finish() override { std::cout << "pongs: " << m_pongs << std::endl; }

private : so_5::rt::mbox_t m_ponger; unsigned int m_pongs = 0;};

SObjectizer Team, Feb 2015

Page 109: Dive into SObjectizer 5.5. Introductory part

Changing of pinger agent (ending): virtual void so_evt_start() override { so_5::send< ping >( m_ponger ); }

virtual void so_evt_finish() override { std::cout << "pongs: " << m_pongs << std::endl; }

private : so_5::rt::mbox_t m_ponger; unsigned int m_pongs = 0;};

Signal sending is performed by the same so_5::send() function. Like a message sending. But there is no any other arguments after receiver mbox.

SObjectizer Team, Feb 2015

Page 110: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; }

virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); }

Similar changes to a ponger agent (beginning):

SObjectizer Team, Feb 2015

Page 111: Dive into SObjectizer 5.5. Introductory part

virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; }

private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0;};

Similar changes to a ponger agent (ending):

SObjectizer Team, Feb 2015

Page 112: Dive into SObjectizer 5.5. Introductory part

Creation of the cooperation becomes more verbose:void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

env.register_coop( std::move( coop ) );}

SObjectizer Team, Feb 2015

Page 113: Dive into SObjectizer 5.5. Introductory part

Creation of the cooperation becomes more verbose:void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

env.register_coop( std::move( coop ) );}

Moreover there is an error...

SObjectizer Team, Feb 2015

Page 114: Dive into SObjectizer 5.5. Introductory part

Creation of the cooperation becomes more verbose:void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

env.register_coop( std::move( coop ) );}

Moreover there is an error…No one stops them!

They will ping each other infinitely.

SObjectizer Team, Feb 2015

Page 115: Dive into SObjectizer 5.5. Introductory part

Fix this problem by adding another agent that will stop example after one second...

SObjectizer Team, Feb 2015

Page 116: Dive into SObjectizer 5.5. Introductory part

Fix this problem by adding another agent that willstop example after one second…

Because this agent will handle only one event there is no need to define a separate class for it, redefine so_define_agent() method and so on...

SObjectizer Team, Feb 2015

Page 117: Dive into SObjectizer 5.5. Introductory part

Fix this problem by adding another agent that willstop example after one second…

Because this agent will handle only one eventthere is no need to define a separate class for it,redefine so_define_agent() method and so on…

An ad-hoc agent will be used instead.

SObjectizer Team, Feb 2015

Page 118: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after one second:

SObjectizer Team, Feb 2015

Page 119: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

SObjectizer Team, Feb 2015

Page 120: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

Stop signal.

SObjectizer Team, Feb 2015

Page 121: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

Ad-hoc agent creation.

A handle is returned. This handle can be used for agent tuning.

SObjectizer Team, Feb 2015

Page 122: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

The new agent is subscribed to just one signal.

SObjectizer Team, Feb 2015

Page 123: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

Signal is expected from direct_mbox of the the agent.

SObjectizer Team, Feb 2015

Page 124: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent for stopping the work after onesecond:

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent();stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

The signal handler will stop SObjectizer Environment.

The single cooperation will be deregistered automatically.

SObjectizer Team, Feb 2015

Page 125: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent is created and tuned.A delayed for one second stop signal must be sent:

SObjectizer Team, Feb 2015

Page 126: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent is created and tuned.A delayed for one second stop signal must be sent:

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );

SObjectizer Team, Feb 2015

Page 127: Dive into SObjectizer 5.5. Introductory part

Ad-hoc agent is created and tuned.A delayed for one second stop signal must be sent:

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );

A so_5::send_delayed function make delayed send of a signal or a message.

In this case a stop signal will be sent to the direct_mbox of the new ad-hoc agent with one second delay.

SObjectizer Team, Feb 2015

Page 128: Dive into SObjectizer 5.5. Introductory part

Finally the starting function becomes:void init( so_5::rt::environment_t & env ){ auto coop = env.create_coop( so_5::autoname );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

SObjectizer Team, Feb 2015

Page 129: Dive into SObjectizer 5.5. Introductory part

Running the updated example...

SObjectizer Team, Feb 2015

Page 130: Dive into SObjectizer 5.5. Introductory part

Running the updated example…

And getting:

pongs: 4441168pings: 4441169

SObjectizer Team, Feb 2015

Page 131: Dive into SObjectizer 5.5. Introductory part

Running the updated example…

And getting:

pongs: 4441168pings: 4441169

Just above 8M messages per seconds.

SObjectizer Team, Feb 2015

Page 132: Dive into SObjectizer 5.5. Introductory part

Running the updated example…

And getting:

pongs: 4441168pings: 4441169

Just above 8M messages per seconds.

Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit,Visual C++ 12.0 64-bit.

SObjectizer Team, Feb 2015

Page 133: Dive into SObjectizer 5.5. Introductory part

Running the updated example…

And getting:

pongs: 4441168pings: 4441169

Just above 8M messages per seconds.

Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit,Visual C++ 12.0 64-bit.

So far, so good. But which working context has been used?

SObjectizer Team, Feb 2015

Page 134: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

SObjectizer Team, Feb 2015

Page 135: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

This example just shows the effectiveness of message passing between agents which are working on the same context.

SObjectizer Team, Feb 2015

Page 136: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

This example just shows the effectiveness ofmessage passing between agents which areworking on the same context.

But who choose the context?And how an agent can be bound to another context?

SObjectizer Team, Feb 2015

Page 137: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

This example just shows the effectiveness ofmessage passing between agents which areworking on the same context.

But who choose the context?And how an agent can be bound to another context?

A programmer makes choice of context when binds an agent to a dispatcher.

SObjectizer Team, Feb 2015

Page 138: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

This example just shows the effectiveness ofmessage passing between agents which areworking on the same context.

But who choose the context?And how an agent can be bound to another context?

A programmer makes choice of context whenbinds an agent to a dispatcher.

If dispatcher is not specified then an agent will be bound to default dispatcher.

SObjectizer Team, Feb 2015

Page 139: Dive into SObjectizer 5.5. Introductory part

All agents were working on a single thread!

This example just shows the effectiveness ofmessage passing between agents which areworking on the same context.

But who choose the context?And how an agent can be bound to another context?

A programmer makes choice of context whenbinds an agent to a dispatcher.

If dispatcher is not specified then an agent will bebound to default dispatcher.

Just like in the example above.SObjectizer Team, Feb 2015

Page 140: Dive into SObjectizer 5.5. Introductory part

The default dispatcher runs all the agents on a single working thread.

There is a something like “cooperative multitasking” for agents on the default dispatcher.

SObjectizer Team, Feb 2015

Page 141: Dive into SObjectizer 5.5. Introductory part

The default dispatcher runs all the agents on asingle working thread.

There is a something like “cooperativemultitasking” for agents on the default dispatcher.

If one of them will slow down the other will slow down too.

SObjectizer Team, Feb 2015

Page 142: Dive into SObjectizer 5.5. Introductory part

The default dispatcher runs all the agents on asingle working thread.

There is a something like “cooperativemultitasking” for agents on the default dispatcher.

If one of them will slow down the other will slowdown too.

But it is possible to create any number of various dispatchers and bind agents to the them.

SObjectizer Team, Feb 2015

Page 143: Dive into SObjectizer 5.5. Introductory part

Lets bind pinger and ponger agent to different working threads (every agent will have its own dedicated working thread)...

SObjectizer Team, Feb 2015

Page 144: Dive into SObjectizer 5.5. Introductory part

Lets bind pinger and ponger agent to differentworking threads (every agent will have its owndedicated working thread)...

An instance of active_obj dispatcher will be created for that. And agents will be bound to it.

SObjectizer Team, Feb 2015

Page 145: Dive into SObjectizer 5.5. Introductory part

Lets bind pinger and ponger agent to differentworking threads (every agent will have its owndedicated working thread)...

An instance of active_obj dispatcher will becreated for that. And agents will be bound to it.

This dispatcher creates a dedicated thread for each agent bound to it (an agent becomes an active object).

SObjectizer Team, Feb 2015

Page 146: Dive into SObjectizer 5.5. Introductory part

There is nothing to change inside the agents...

SObjectizer Team, Feb 2015

Page 147: Dive into SObjectizer 5.5. Introductory part

There is nothing to change inside the agents…

All the changes will be in the starting function only.

SObjectizer Team, Feb 2015

Page 148: Dive into SObjectizer 5.5. Introductory part

Binding of the agents to different dispatches:void init( so_5::rt::environment_t & env ){ env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

SObjectizer Team, Feb 2015

Page 149: Dive into SObjectizer 5.5. Introductory part

Binding of the agents to different dispatches:void init( so_5::rt::environment_t & env ){ env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

A request for creation of the active objects dispatcher with name “active_obj”. If there is no such dispatcher it will be created by the factory specified.

SObjectizer Team, Feb 2015

Page 150: Dive into SObjectizer 5.5. Introductory part

Binding of the agents to different dispatches:void init( so_5::rt::environment_t & env ){ env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

A main dispatcher for the cooperation will be the dispatcher with name “active_obj”.

SObjectizer Team, Feb 2015

Page 151: Dive into SObjectizer 5.5. Introductory part

Binding of the agents to different dispatches:void init( so_5::rt::environment_t & env ){ env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

Pinger and ponger agents are being added to the cooperation without any additional information. It means they will be bound to the main cooperation dispatcher. The dispatcher with name “active_obj” in that case.

SObjectizer Team, Feb 2015

Page 152: Dive into SObjectizer 5.5. Introductory part

Binding of the agents to different dispatches:void init( so_5::rt::environment_t & env ){ env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") );

auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) );

a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

struct stop : public so_5::rt::signal_t {};

auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );

env.register_coop( std::move( coop ) );

so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );}

But there is no need for a separate thread for stopper agent. Because of that this agent is being bound to the default dispatcher explicitly. Without this the stopper will be bound to the cooperation main dispatcher.

SObjectizer Team, Feb 2015

Page 154: Dive into SObjectizer 5.5. Introductory part

What we get now?

pings: pongs: 12346231234624

SObjectizer Team, Feb 2015

Page 155: Dive into SObjectizer 5.5. Introductory part

What we get now?

pings: pongs: 12346231234624

Is it ok?

SObjectizer Team, Feb 2015

Page 156: Dive into SObjectizer 5.5. Introductory part

What we get now?

pings: pongs: 12346231234624

Is it ok?

Yes. It is.

SObjectizer Team, Feb 2015

Page 157: Dive into SObjectizer 5.5. Introductory part

What we get now?

pings: pongs: 12346231234624

Is it ok?

Yes. It is.And there could be more strange results.

SObjectizer Team, Feb 2015

Page 158: Dive into SObjectizer 5.5. Introductory part

pings: pongs: 12346231234624

But what happened?

SObjectizer Team, Feb 2015

Page 159: Dive into SObjectizer 5.5. Introductory part

pings: pongs: 12346231234624

But what happened?

Pinger and ponger agents are now working on different threads and compete for std::cout object. As result the output to std::cout got mixed. It could be even worse. Or could not be mixed at all.Concurrency in action...

SObjectizer Team, Feb 2015

Page 160: Dive into SObjectizer 5.5. Introductory part

pings: pongs: 12346231234624

What else?

SObjectizer Team, Feb 2015

Page 161: Dive into SObjectizer 5.5. Introductory part

pings: pongs: 12346231234624

What else?

The performance has dropped. We have seen 8M messages per second on one thread. And just 2M on two threads.

SObjectizer Team, Feb 2015

Page 162: Dive into SObjectizer 5.5. Introductory part

pings: pongs: 12346231234624

What else?

The performance has dropped. We have seen 8Mmessages per second on one thread. And just 2Mon two threads.

It is expected result. Passing a single message from thread to thread is an expensive operation.

SObjectizer Team, Feb 2015

Page 163: Dive into SObjectizer 5.5. Introductory part

But is there any changes in the agents?

SObjectizer Team, Feb 2015

Page 164: Dive into SObjectizer 5.5. Introductory part

But is there any changes in the agents?

NO!

SObjectizer Team, Feb 2015

Page 165: Dive into SObjectizer 5.5. Introductory part

Ponger agent for one thread:class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; }

virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); }

virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; }

private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0;};

SObjectizer Team, Feb 2015

Page 166: Dive into SObjectizer 5.5. Introductory part

class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; }

virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); }

virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; }

private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0;};

Ponger agent for two threads:class ponger : public so_5::rt::agent_t{public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; }

virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); }

virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; }

private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0;};

SObjectizer Team, Feb 2015

Ponger agent for one thread:

Page 167: Dive into SObjectizer 5.5. Introductory part

It is a direct consequence of interaction only by asynchronous messages.

SObjectizer Team, Feb 2015

Page 168: Dive into SObjectizer 5.5. Introductory part

It is a direct consequence of interaction only by asynchronous messages.

Because of that agents are unaware about working context.

SObjectizer Team, Feb 2015

Page 169: Dive into SObjectizer 5.5. Introductory part

It is a direct consequence of interaction only byasynchronous messages.

Because of that agents are unaware aboutworking context.

Providing an appropriate set of different dispatcher is a task of SObjectizer.

SObjectizer Team, Feb 2015

Page 170: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:

SObjectizer Team, Feb 2015

Page 171: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:● one_thread. All agents work on a single working thread;

SObjectizer Team, Feb 2015

Page 172: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:● one_thread. All agents work on a single working thread;● active_obj. Every agent works on a single dedicated working thread;

SObjectizer Team, Feb 2015

Page 173: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:● one_thread. All agents work on a single working thread;● active_obj. Every agent works on a single dedicated working thread;● active_group. A single dedicated working thread is allocated for a group

of agents;

SObjectizer Team, Feb 2015

Page 174: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:● one_thread. All agents work on a single working thread;● active_obj. Every agent works on a single dedicated working thread;● active_group. A single dedicated working thread is allocated for a group

of agents;● thread_pool. A working thread is selected from thread pool. Agents can

be moved from one working thread to another. But an agent can’t work on two threads at the same time;

SObjectizer Team, Feb 2015

Page 175: Dive into SObjectizer 5.5. Introductory part

SObjectizer has several ready-to-use dispatchers:● one_thread. All agents work on a single working thread;● active_obj. Every agent works on a single dedicated working thread;● active_group. A single dedicated working thread is allocated for a group

of agents;● thread_pool. A working thread is selected from thread pool. Agents can

be moved from one working thread to another. But an agent can’t work on two threads at the same time;

● adv_thread_pool. A working thread is selected from thread pool. Agents can be moved from one working thread to another. Moreover an agent can work on several threads at the same time (if the agent’s event handlers are marked as thread safe).

SObjectizer Team, Feb 2015

Page 176: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type of a dispatcher...

SObjectizer Team, Feb 2015

Page 177: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

SObjectizer Team, Feb 2015

Page 178: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:

SObjectizer Team, Feb 2015

Page 179: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:● one one_thread dispatcher for AMQP-client agent;

SObjectizer Team, Feb 2015

Page 180: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:● one one_thread dispatcher for AMQP-client agent;● one thread_pool dispatcher for handling requests from AMQP-queues;

SObjectizer Team, Feb 2015

Page 181: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:● one one_thread dispatcher for AMQP-client agent;● one thread_pool dispatcher for handling requests from AMQP-queues;● one active_obj dispatcher for DBMS-related agents;

SObjectizer Team, Feb 2015

Page 182: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:● one one_thread dispatcher for AMQP-client agent;● one thread_pool dispatcher for handling requests from AMQP-queues;● one active_obj dispatcher for DBMS-related agents;● yet another active_obj dispatcher for agents whose work with HSMs

connected to the computer;

SObjectizer Team, Feb 2015

Page 183: Dive into SObjectizer 5.5. Introductory part

A programmer can not only select the appropriate type ofa dispatcher…

...but can create any number of those dispatchers.

For example:● one one_thread dispatcher for AMQP-client agent;● one thread_pool dispatcher for handling requests from AMQP-queues;● one active_obj dispatcher for DBMS-related agents;● yet another active_obj dispatcher for agents whose work with HSMs

connected to the computer;● and yet another thread_pool dispatcher for agents for managing all the

stuff described above.

SObjectizer Team, Feb 2015

Page 184: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features...

SObjectizer Team, Feb 2015

Page 185: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:

SObjectizer Team, Feb 2015

Page 186: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states

SObjectizer Team, Feb 2015

Page 187: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages

SObjectizer Team, Feb 2015

Page 188: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction

SObjectizer Team, Feb 2015

Page 189: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction● child cooperation

SObjectizer Team, Feb 2015

Page 190: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction● child cooperation● exception handling

SObjectizer Team, Feb 2015

Page 191: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction● child cooperation● exception handling● Run-Time parameters tuning and so on...

SObjectizer Team, Feb 2015

Page 192: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction● child cooperation● exception handling● Run-Time parameters tuning and so on…

...will be described in a more deep dive

SObjectizer Team, Feb 2015

Page 193: Dive into SObjectizer 5.5. Introductory part

But there are yet more SObjectizer features…

Such important things like:● agent’s states● periodic messages● synchronous agents interaction● child cooperation● exception handling● Run-Time parameters tuning and so on…

...will be described in a more deep dive

But introductory part is finished.

SObjectizer Team, Feb 2015

Page 194: Dive into SObjectizer 5.5. Introductory part

Additional Information:

Project’s home: http://sourceforge.net/projects/sobjectizer

Documentation: http://sourceforge.net/p/sobjectizer/wiki/

Forum: http://sourceforge.net/p/sobjectizer/discussion/

Google-group: https://groups.google.com/forum/#!forum/sobjectizer