#include <so_5/all.hpp>
class shutdown_initiator_t final : public so_5::agent_t
{
state_t st_wait_shutdown_start{ this };
state_t st_wait_shutdown_finish{ this };
struct tick final : public so_5::signal_t {};
public :
shutdown_initiator_t( context_t ctx )
: so_5::agent_t( std::move(ctx) )
{
this >>= st_wait_shutdown_start;
st_wait_shutdown_start.event( &shutdown_initiator_t::on_tick_1 );
st_wait_shutdown_finish.event( &shutdown_initiator_t::on_tick_2 );
}
virtual void so_evt_start() override
{
m_timer = so_5::send_periodic< tick >( *this,
std::chrono::seconds::zero(),
std::chrono::seconds(1) );
}
virtual void so_evt_finish() override
{
std::cout << "Application finally finishes..." << std::endl;
}
private :
so_5::timer_id_t m_timer;
int m_counter = 3;
void on_tick_1( mhood_t<tick> )
{
if( 0 < m_counter )
{
std::cout << "Stop in " << m_counter << " second(s)..." << std::endl;
--m_counter;
}
else
{
std::cout << "Stop started!" << std::endl;
this >>= st_wait_shutdown_finish;
so_environment().stop();
}
}
void on_tick_2( mhood_t<tick> )
{
++m_counter;
std::cout << "Shutdown is in progress for " << m_counter << " second(s)"
<< std::endl;
}
};
class worker_t final : public so_5::agent_t
{
state_t st_normal{ this };
state_t st_shutting_down{ this };
struct tick final : public so_5::signal_t {};
public :
worker_t(
context_t ctx,
std::string name,
std::chrono::steady_clock::duration tick_size,
unsigned int ticks_before_shutdown )
:
so_5::agent_t( std::move(ctx) )
, m_name( std::move(name) )
, m_tick_size( tick_size )
, m_ticks_before_shutdown( ticks_before_shutdown )
{
this >>= st_normal;
st_normal.event(
&worker_t::on_shutdown_initiated );
st_shutting_down
.on_enter( [this] {
m_timer = so_5::send_periodic< tick >( *this,
std::chrono::seconds::zero(),
m_tick_size );
} )
.event( &worker_t::on_tick );
}
virtual void so_evt_finish() override
{
std::cout << "worker: " << m_name << ", finished!" << std::endl;
}
private :
const std::string m_name;
const std::chrono::steady_clock::duration m_tick_size;
unsigned int m_ticks_before_shutdown;
so_5::timer_id_t m_timer;
void on_shutdown_initiated( mhood_t<so_5::extra::shutdowner::shutdown_initiated_t> )
{
std::cout << "worker: " << m_name << ", shutdown started." << std::endl;
this >>= st_shutting_down;
}
void on_tick( mhood_t<tick> )
{
using namespace std::chrono;
std::cout << "worker: " << m_name << ", stop in "
<< duration_cast< milliseconds >(m_tick_size *
m_ticks_before_shutdown).count() << "ms" << std::endl;
if( !m_ticks_before_shutdown )
so_deregister_agent_coop_normally();
else
--m_ticks_before_shutdown;
}
};
void make_worker(
so_5::environment_t & env,
std::string name,
std::chrono::steady_clock::duration tick_size,
unsigned int ticks_before_shutdown )
{
env.introduce_coop( [&]( so_5::coop_t & coop ) {
coop.make_agent< worker_t >(
std::move(name),
tick_size,
ticks_before_shutdown );
} );
}
void run_example()
{
so_5::launch( []( so_5::environment_t & env ) {
env.introduce_coop( []( so_5::coop_t & coop ) {
coop.make_agent< shutdown_initiator_t >();
} );
make_worker( env, "worker-1", std::chrono::milliseconds(250), 5u );
make_worker( env, "worker-2", std::chrono::milliseconds(350), 6u );
make_worker( env, "worker-3", std::chrono::milliseconds(750), 3u );
make_worker( env, "worker-4", std::chrono::milliseconds(150), 10u );
make_worker( env, "worker-5", std::chrono::milliseconds(0), 0u );
},
[]( so_5::environment_params_t & params ) {
params.add_layer(
std::chrono::seconds(15) ) );
} );
}
int main()
{
try
{
run_example();
return 0;
}
catch( const std::exception & x )
{
std::cerr << "Exception caught: " << x.what() << std::endl;
}
return 2;
}
Ranges for error codes of each submodules.
Implementation of shutdowner-related stuff.