diff --git a/dev/sample/so_5/CMakeLists.txt b/dev/sample/so_5/CMakeLists.txt index 2401356f..9904ed80 100644 --- a/dev/sample/so_5/CMakeLists.txt +++ b/dev/sample/so_5/CMakeLists.txt @@ -81,4 +81,5 @@ add_subdirectory(unique_subscribers_mbox) add_subdirectory(introduce_named_mbox) add_subdirectory(child_soenv) add_subdirectory(bind_transformer) +add_subdirectory(agent_name) diff --git a/dev/sample/so_5/agent_name/CMakeLists.txt b/dev/sample/so_5/agent_name/CMakeLists.txt new file mode 100644 index 00000000..8ee8102a --- /dev/null +++ b/dev/sample/so_5/agent_name/CMakeLists.txt @@ -0,0 +1,9 @@ +set(SAMPLE sample.so_5.agent_name) +add_executable(${SAMPLE} main.cpp) +target_link_libraries(${SAMPLE} sobjectizer::SharedLib) +install(TARGETS ${SAMPLE} DESTINATION bin) + +set(SAMPLE_S sample.so_5.agent_name_s) +add_executable(${SAMPLE_S} main.cpp) +target_link_libraries(${SAMPLE_S} sobjectizer::StaticLib) +install(TARGETS ${SAMPLE_S} DESTINATION bin) diff --git a/dev/sample/so_5/agent_name/main.cpp b/dev/sample/so_5/agent_name/main.cpp new file mode 100644 index 00000000..aa7314b6 --- /dev/null +++ b/dev/sample/so_5/agent_name/main.cpp @@ -0,0 +1,190 @@ +/* + * A sample of usage of agent name. + */ + +#include + +#include +#include + +// Name of mbox for sending information to agents registry. +const std::string registry_mbox_name{ "agents_registry" }; + +// Agent that plays role of agents registry. +class agents_registry final : public so_5::agent_t +{ +public: + // Message for informing about start of an agent. + struct agent_started final : public so_5::message_t + { + const std::string m_name; + + agent_started( std::string name ) : m_name{ std::move(name) } + {} + }; + + // Message for informing that agent finished its work. + struct agent_finished final : public so_5::message_t + { + const std::string m_name; + + agent_finished( std::string name ) : m_name{ std::move(name) } + {} + }; + + agents_registry( context_t ctx ) + : so_5::agent_t{ std::move(ctx) } + {} + + void so_define_agent() override + { + so_subscribe( so_environment().create_mbox( registry_mbox_name ) ) + .event( &agents_registry::evt_agent_started ) + .event( &agents_registry::evt_agent_finished ) + ; + + so_subscribe_self() + .event( &agents_registry::evt_show_registry ) + ; + } + + void so_evt_start() override + { + // Initiate periodic message for showing the content of the registry. + m_show_timer = so_5::send_periodic< show_registry >( *this, + std::chrono::milliseconds{ 20 }, + std::chrono::milliseconds{ 20 } ); + } + +private: + // Periodic signal for showing the current content of the registry. + struct show_registry final : public so_5::signal_t {}; + + // A list of currently working agents. + std::set< std::string > m_registry; + + // Timer for showing the current content of the registry. + so_5::timer_id_t m_show_timer; + + void evt_agent_started( mhood_t cmd ) + { + m_registry.insert( cmd->m_name ); + + std::cout << " started: " << cmd->m_name << std::endl; + } + + void evt_agent_finished( mhood_t cmd ) + { + m_registry.erase( cmd->m_name ); + + std::cout << "finished: " << cmd->m_name << std::endl; + + if( m_registry.empty() ) + // It's time to complete. + so_deregister_agent_coop_normally(); + } + + void evt_show_registry( mhood_t ) + { + std::cout << "--- registry begin ---" << std::endl; + for( const auto & name : m_registry ) + std::cout << " " << name << std::endl; + std::cout << "--- registry end ---" << std::endl; + } +}; + +// Base class for worker. Agents of this type have no names. +class simple_worker : public so_5::agent_t +{ +public: + simple_worker( context_t ctx, std::chrono::milliseconds work_time ) + : so_5::agent_t{ std::move(ctx) } + , m_work_time{ work_time } + {} + + void so_define_agent() override + { + so_subscribe_self().event( &simple_worker::evt_done ); + } + + void so_evt_start() override + { + // Should inform about the start. + so_5::send< agents_registry::agent_started >( + so_environment().create_mbox( registry_mbox_name ), + so_agent_name().to_string() ); + + // Limit the work time. + so_5::send_delayed< done >( *this, m_work_time ); + } + + void so_evt_finish() override + { + // Should inform about the finish. + so_5::send< agents_registry::agent_finished >( + so_environment().create_mbox( registry_mbox_name ), + so_agent_name().to_string() ); + } + +private: + // Signal for limiting work time of the agent. + struct done final : public so_5::signal_t {}; + + // How long the agent should work. + const std::chrono::milliseconds m_work_time; + + void evt_done( mhood_t ) + { + so_deregister_agent_coop_normally(); + } +}; + +// Type of worker with name. +// +// It's derived from simple_worker just to make example code shorter. +class named_worker : public simple_worker +{ +public: + named_worker( context_t ctx, std::string_view name, std::chrono::milliseconds work_time ) + : simple_worker{ ctx + name_for_agent(name), work_time } + {} + + // There is no need to define something else. +}; + +int main() +{ + try + { + // Starting SObjectizer. + so_5::launch( + // A function for SO Environment initialization. + []( so_5::environment_t & env ) + { + // Starting the registry. + env.register_agent_as_coop( + env.make_agent< agents_registry >() ); + + // Starting workers. + using namespace std::chrono_literals; + env.register_agent_as_coop( + env.make_agent< simple_worker >( 30ms ) ); + env.register_agent_as_coop( + env.make_agent< simple_worker >( 50ms ) ); + env.register_agent_as_coop( + env.make_agent< named_worker >( "Alice", 50ms ) ); + env.register_agent_as_coop( + env.make_agent< simple_worker >( 70ms ) ); + env.register_agent_as_coop( + env.make_agent< named_worker >( "Bob", 90ms ) ); + } ); + } + catch( const std::exception & ex ) + { + std::cerr << "Error: " << ex.what() << std::endl; + return 1; + } + + return 0; +} + diff --git a/dev/sample/so_5/agent_name/prj.rb b/dev/sample/so_5/agent_name/prj.rb new file mode 100644 index 00000000..1cdb1f94 --- /dev/null +++ b/dev/sample/so_5/agent_name/prj.rb @@ -0,0 +1,10 @@ +require 'mxx_ru/cpp' + +MxxRu::Cpp::exe_target { + + required_prj 'so_5/prj.rb' + target 'sample.so_5.agent_name' + + cpp_source 'main.cpp' +} + diff --git a/dev/sample/so_5/agent_name/prj_s.rb b/dev/sample/so_5/agent_name/prj_s.rb new file mode 100644 index 00000000..f84b1ec4 --- /dev/null +++ b/dev/sample/so_5/agent_name/prj_s.rb @@ -0,0 +1,10 @@ +require 'mxx_ru/cpp' + +MxxRu::Cpp::exe_target { + + required_prj 'so_5/prj_s.rb' + target 'sample.so_5.agent_name_s' + + cpp_source 'main.cpp' +} + diff --git a/dev/sample/so_5/build_samples.rb b/dev/sample/so_5/build_samples.rb index 4ac0441d..4655615f 100644 --- a/dev/sample/so_5/build_samples.rb +++ b/dev/sample/so_5/build_samples.rb @@ -87,4 +87,5 @@ example[ 'introduce_named_mbox' ] example[ 'child_soenv' ] example[ 'bind_transformer' ] + example[ 'agent_name' ] } diff --git a/dev/test/so_5/samples_as_unit_tests/agent_name-static.ut.rb b/dev/test/so_5/samples_as_unit_tests/agent_name-static.ut.rb new file mode 100644 index 00000000..becc324f --- /dev/null +++ b/dev/test/so_5/samples_as_unit_tests/agent_name-static.ut.rb @@ -0,0 +1,3 @@ +require_relative 'details.rb' + +setup_sample_as_unit_test diff --git a/dev/test/so_5/samples_as_unit_tests/agent_name.ut.rb b/dev/test/so_5/samples_as_unit_tests/agent_name.ut.rb new file mode 100644 index 00000000..becc324f --- /dev/null +++ b/dev/test/so_5/samples_as_unit_tests/agent_name.ut.rb @@ -0,0 +1,3 @@ +require_relative 'details.rb' + +setup_sample_as_unit_test diff --git a/dev/test/so_5/samples_as_unit_tests/build_tests.rb b/dev/test/so_5/samples_as_unit_tests/build_tests.rb index bc3f3e71..38fa0ba3 100644 --- a/dev/test/so_5/samples_as_unit_tests/build_tests.rb +++ b/dev/test/so_5/samples_as_unit_tests/build_tests.rb @@ -112,5 +112,7 @@ required_prj "#{path}/bind_transformer.ut.rb" required_prj "#{path}/bind_transformer-static.ut.rb" -} + required_prj "#{path}/agent_name.ut.rb" + required_prj "#{path}/agent_name-static.ut.rb" +} diff --git a/doxygen/dox/so_5/samples.dox b/doxygen/dox/so_5/samples.dox index 7b0c9960..0459d3f9 100644 --- a/doxygen/dox/so_5/samples.dox +++ b/doxygen/dox/so_5/samples.dox @@ -1,5 +1,6 @@ /*! * \example so_5/adv_thread_pool_fifo/main.cpp + * \example so_5/agent_name/main.cpp * \example so_5/bind_transformer/main.cpp * \example so_5/blinking_led/main.cpp * \example so_5/chameneos_prealloc_msgs/main.cpp