Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Dive into SObjectizer 5.5. Second part. States

570 views

Published on

This is the second part of the serie of presentations with deep introduction into features of SObjectizer-5.5.

This part is dedicated to such important feature as agent's states.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Dive into SObjectizer 5.5. Second part. States

  1. 1. Dive into SObjectizer-5.5 SObjectizer Team, Jan 2016 Second Part: Agent’s States at v.5.5.15
  2. 2. The main features of SObjectizer-5.5, like agents, cooperations, messages/signal, mboxes, dispatchers and delayed delivery, were described in the previous part. The next important feature is agent’s state. SObjectizer Team, Jan 2016
  3. 3. Agent in SObjectizer is a finite-state machine. The behaviour of an agent depends on the current state of the agent and the received message. SObjectizer Team, Jan 2016
  4. 4. An agent can receive and process different messages in each state. In other words an agent can receive a message in one state but ignore it in another state. Or, if an agent receives the same message in several states, it can handle the message differently in each state. SObjectizer Team, Jan 2016
  5. 5. Where it can be useful? SObjectizer Team, Jan 2016
  6. 6. Let’s imagine a simple agent which controls LED indicator on some device. It receives just one signal turn_on_off. When LED indicator is off this signal should turn indicator on. If LED indicator is on this signal should turn indicator off. SObjectizer Team, Jan 2016
  7. 7. This logic can be represented by simple statechart: SObjectizer Team, Jan 2016 off on enter/turn_led_on exit/turn_led_off turn_on_off turn_on_off
  8. 8. It's easy to see that led_indicator agent requires two states: off and on. They can be directly expressed in C++ code via usage of so_5::state_t class. The definition of new state for an agent means creation of new instance of state_t. SObjectizer Team, Jan 2016
  9. 9. States are usually represented as members of agent’ s class: class led_indicator final : public so_5::agent_t { state_t off{ this }, on{ this }; SObjectizer Team, Jan 2016
  10. 10. A state can have a textual name: class led_indicator final : public so_5::agent_t { state_t off{ this, "off" }, on{ this, "on" }; It could be useful for debugging and logging. SObjectizer Team, Jan 2016
  11. 11. There are several ways of changing agent’s state: // Very old and basic way. so_change_state( off ); // More modern and short way. off.activate(); // Yet more modern way. this >>= off; The current state can be obtained via so_current_state() method: if( off == so_current_state() ) … SObjectizer Team, Jan 2016
  12. 12. Every agent already has one state: the default one. The default state can be accessed via so_default_state() method: // Returning agent to the default state. this >>= so_default_state(); SObjectizer Team, Jan 2016
  13. 13. Even ad-hoc agents have the default state. But it is the only one state they have. Because there is no user-defined class for an ad-hoc agent then there is no possibility to define new states for ad-hoc agent. Thus there is no possibility to change state of ad-hoc agent. SObjectizer Team, Jan 2016
  14. 14. The most important part of usage of agent’s states is subscription to a message with respect to a specific state... SObjectizer Team, Jan 2016
  15. 15. The simple usage of so_subscribe() and so_subscribe_self() methods leads to subscription only for the default agent’s state. It means that: so_subscribe_self().event(…); is the equivalent of: so_subscribe_self().in( so_default_state() ).event(…); SObjectizer Team, Jan 2016
  16. 16. To make subscription to a message for a specific state it is necessary to use in() method in a subscription chain: so_subscribe_self().in( off ).event(…); so_subscribe_self().in( on ).event(…); SObjectizer Team, Jan 2016
  17. 17. The in() methods can be chained if the same event handler is used in several states: so_subscribe_self() .in( off ) .in( on ) .event< get_name >( [] -> std::string { return "led_indicator"; } ); so_subscribe_self() .in( off ) .event< get_status >( [] -> std::string { return "off"; } ); SObjectizer Team, Jan 2016
  18. 18. There is another way to make subscription for a specific state: off.event< get_name >( [] -> std::string { return "led_indicator"; } ) .event< get_status >( [] -> std::string { return "off"; } ); on.event< get_name >( [] -> std::string { return "led_indicator"; } ) .event(...) ...; SObjectizer Team, Jan 2016
  19. 19. There are also on_enter/on_exit methods in state_t class. Method on_enter sets up an enter handler. Enter handler is automatically called when the state is activated. Contrary on_exit method sets an exit handler. Exit handler is automatically called when the state is activated. Enter and exit handler can be a lambda-function or a pointer to member method of agent's class. SObjectizer Team, Jan 2016
  20. 20. In the led_indicator example enter and exit handlers are necessary for on state: on.on_enter( [this]{ /* some device-dependent code */ } ) .on_exit( [this]{ /* some device-dependent code */ } ) ... SObjectizer Team, Jan 2016
  21. 21. Let’s see a full example of led_indicator agent. SObjectizer Team, Jan 2016
  22. 22. The full led_indicator agent code: class led_indicator final : public so_5::agent_t { state_t off{ this, "off" }, on{ this, "on" }; public : struct turn_on_off : public so_5::signal_t {}; led_indicator( context_t ctx ) : so_5::agent_t{ ctx } { this >>= off; off.event< turn_on_off >( [this]{ this >>= on; } ); on.on_enter( [this]{ /* some device-dependent code */ } ) .on_exit( [this]{ /* some device-dependent code */ } ) .event< turn_on_off >( [this]{ this >>= off; } ); } }; SObjectizer Team, Jan 2016
  23. 23. A few more things must be mentioned in the code above... SObjectizer Team, Jan 2016
  24. 24. The first one is the place where all subscription is defined. In led_indicator example agent definition is performed in the agent's constructor. Usually all agent definition is done in so_define_agent() method. It has sense if class inheritance is used. But led_indicator is final class so we can do all these actions in led_indicator's constructor. SObjectizer Team, Jan 2016
  25. 25. The second one is switching of led_indicator agent to off state. By default the initial state of any agent is the default state (which is accessible via so_default_state() method). But we need to start led_indicator agent in off state. So we change agent's state at the very beginning. SObjectizer Team, Jan 2016
  26. 26. The third one is the guarantee of calling exit handler for state. If an agent enters into state S and state S has exit handler then SObjectizer guarantees the invocation of that exit handler in case of: ● switching of agent to different state; ● so_evt_finish() for agent is called (as a result of agent's coop deregistration or SObjectizer Environment shutdown). SObjectizer Team, Jan 2016
  27. 27. The example shown above demonstrate simple finite- state machine. Since v.5.5.15 SObjectizer supports more advanced features of agents' states like composite states, shallow- and deep-history, time limitations and so on. These advanced features allow to implement agents as hierarchical state machines. SObjectizer Team, Jan 2016
  28. 28. Let's see an ability to create hierarchical state machines on a slightly complex example: an agent which implements blinking of LED indicator. This agent receives `turn_on_off` signal for turning blinking on and off. When blinking is turned on then agent switches LED indicator on for 1s then switches it off for 1s then switches on again and so on until the agent receives next `turn_on_off` signal. SObjectizer Team, Jan 2016
  29. 29. A statechart for that agent can be represented as: SObjectizer Team, Jan 2016 off blinking enter/turn_timer_on exit/turn_timer_off turn_on_off turn_on_off blink_on enter/turn_led_on exit/turn_led_off blink_off timer timer
  30. 30. Declaration of agent's states: class blinking_led final : public so_5::agent_t { state_t off{ this, "off" }, blinking{ this, "blinking" }, blink_on{ initial_substate_of{ blinking }, "on" }, blink_off{ substate_of{ blinking }, "off" }; Agent has two top level states: off and blinking. State blinking is a composite state with two substates: blink_on and blink_off. SObjectizer Team, Jan 2016
  31. 31. Substate blink_on is marked as initial substate of composite state blinking. It means that when state blinking is activated then substate blink_on is activated too. Moreover so_current_state() method will return a reference to blink_on, not to blinking. It is because so_current_state() always returns a reference to a leaf state in agent's state tree. SObjectizer Team, Jan 2016
  32. 32. Every composite state must have the initial substate. It means that exactly one substate must be declared by using initial_substate_of indicator: blink_on{ initial_substate_of{ blinking }, "on" }, blink_off{ substate_of{ blinking }, "off" }; An attempt to activate a composite state without the initial substate defined will lead to an error at run-time. SObjectizer Team, Jan 2016
  33. 33. Behaviour of a state can be defined anywhere in the agent's code. Usually it is done in agent's constructor or in so_define_agent() method. Definition of state's behaviour inside so_define_agent() is preferable if inheritance of agent's classes is required or indented. In this example inheritance is not used so we define behaviour of agent's state in the agent's constructor: SObjectizer Team, Jan 2016
  34. 34. Definition of states behaviour: off .event< turn_on_off >( [this]{ this >>= blinking; } ); blinking .on_enter( [this] { m_timer = so_5::send_periodic< timer >( *this, std::chrono::seconds::zero(), std::chrono::seconds{1} ); } ) .on_exit( [this]{ m_timer.release(); } ) .event< turn_on_off >( [this]{ this >>= off; } ); blink_on .on_enter( &blinking_led::led_on ) .on_exit( &blinking_led::led_off ) .event< timer >( [this]{ this >>= blink_off; } ); blink_off .event< timer >( [this]{ this >>= blink_on; } ); SObjectizer Team, Jan 2016
  35. 35. It's easy to see that many events look like: event<Message>([this] { this >>= State; }); This is very typical case in complex statecharts. There is a special method just_switch_to() which can simplify such cases. By using this method we can rewrite states behaviour that way: SObjectizer Team, Jan 2016
  36. 36. Definition of states behaviour with just_switch_to: off .just_switch_to< turn_on_off >( blinking ); blinking .on_enter( [this] { m_timer = so_5::send_periodic< timer >( *this, std::chrono::seconds::zero(), std::chrono::seconds{1} ); } ) .on_exit( [this]{ m_timer.release(); } ) .just_switch_to< turn_on_off >( off ); blink_on .on_enter( &blinking_led::led_on ) .on_exit( &blinking_led::led_off ) .just_switch_to< timer >( blink_off ); blink_off .just_switch_to< timer >( blink_on ); SObjectizer Team, Jan 2016
  37. 37. Note that reaction to turn_on_off signal is defined only in off and blinking states. There are no such handles in substates blink_on and blink_off. It is not necessary because substates inherit event handlers from their parent states. SObjectizer Team, Jan 2016
  38. 38. Inheritance of event handlers means that event handler will be searched in the current state, then in its parent state, then in its parent state and so on... In blinking_led agent an event handler for turn_on_off signal will be searched in blink_on and blink_off states and then in blinking state. That is why we don't need to create subscription for turn_on_off in blink_on and blink_off states. SObjectizer Team, Jan 2016
  39. 39. The full source for blinking_led agent (1/3): class blinking_led final : public so_5::agent_t { state_t off{ this, "off" }, blinking{ this, "blinking" }, blink_on{ initial_substate_of{ blinking }, "on" }, blink_off{ substate_of{ blinking }, "off" }; struct timer : public so_5::signal_t {}; public : struct turn_on_off : public so_5::signal_t {}; SObjectizer Team, Jan 2016
  40. 40. The full source for blinking_led agent (2/3): blinking_led( context_t ctx ) : so_5::agent_t{ ctx } { this >>= off; off .just_switch_to< turn_on_off >( blinking ); blinking .on_enter( [this] { m_timer = so_5::send_periodic< timer >( *this, std::chrono::seconds::zero(), std::chrono::seconds{1} ); } ) .on_exit( [this]{ m_timer.release(); } ) .just_switch_to< turn_on_off >( off ); SObjectizer Team, Jan 2016
  41. 41. The full source for blinking_led agent (3/3): blink_on .on_enter( &blinking_led::led_on ) .on_exit( &blinking_led::led_off ) .just_switch_to< timer >( blink_off ); blink_off .just_switch_to< timer >( blink_on ); } private : so_5::timer_id_t m_timer; void led_on() { /* some device-dependent code */ } void led_off() { /* some device-dependent code */ } }; SObjectizer Team, Jan 2016
  42. 42. There are several other features which simplify implementation of complex state machines. One of them can simplify blinking_led example show above. It is time_limit for agent's state. SObjectizer Team, Jan 2016
  43. 43. Let's imagine that blinking_led agent have to switch LED on for 1.5s and then switch it off for 0.7s. How can we do that? The obvious way is to use delayed signals with different timeouts in enter handlers for blink_on and blink_off states. But this way is not very easy in fact... Usage of time_limit is much simpler. SObjectizer Team, Jan 2016
  44. 44. Just remove timer signal and m_timer_id from blinking_led agent and rewrite states behaviour that way: off .just_switch_to< turn_on_off >( blinking ); blinking .just_switch_to< turn_on_off >( off ); blink_on .on_enter( &blinking_led::led_on ) .on_exit( &blinking_led::led_off ) .time_limit( std::chrono::milliseconds{1500}, blink_off ); blink_off .time_limit( std::chrono::milliseconds{750}, blink_on ); SObjectizer Team, Jan 2016
  45. 45. The time_limit feature dictates SObjectizer to limit time spent in the specific state. A clause like: SomeState.time_limit(Timeout, AnotherState); tells the SObjectizer that agent must be automatically switched from SomeState to AnotherState after Timeout spent in SomeState. SObjectizer Team, Jan 2016
  46. 46. The blinking_led example shows just few advanced features of agent's states. Some features like shallow- and deep-history and transfer_to_state/suppress methods are not described here. Please see the more detailed description of these features in the Project's Wiki. SObjectizer Team, Jan 2016
  47. 47. 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 GitHub mirror: https://github.com/masterspline/SObjectizer

×