#include <chrono>
#include <cstdlib>
#include <ctime>
#include <deque>
#include <iostream>
#include <sstream>
#include <string>
#include <random>
using namespace std::chrono_literals;
struct request_base
{
int m_id;
request_base( int id ) : m_id{ id } {}
};
struct req_A final : request_base {};
struct req_B final : request_base {};
struct req_C final : request_base {};
struct req_D final : request_base {};
struct req_E final : request_base {};
struct req_F final : request_base {};
struct req_G final : request_base {};
struct req_I final : request_base {};
struct log_message
{
std::string m_what;
};
{
public :
a_logger_t( context_t ctx )
+ limit_then_abort< log_message >( 100 ) )
, m_started_at( std::chrono::steady_clock::now() )
{}
{
[this]( const log_message & evt ) {
std::cout << "[+" << time_delta()
<< "] -- " << evt.m_what << std::endl;
} );
}
private :
const std::chrono::steady_clock::time_point m_started_at;
std::string time_delta() const
{
auto now = std::chrono::steady_clock::now();
std::ostringstream ss;
ss << double(
std::chrono::duration_cast< std::chrono::milliseconds >(
now - m_started_at ).count()
) / 1000.0 << "ms";
return ss.str();
}
};
{
template< typename Request >
[[nodiscard]]
auto
make_event_handler( std::string name )
{
return [this, req_name=std::move(name)]( mhood_t<Request> cmd ) {
req_name + ": redirected to trash can, id=" +
std::to_string(cmd->m_id) );
};
}
public :
a_trash_can_t(
context_t ctx,
+ limit_then_drop< any_unspecified_message >( 10u )
}
, m_logger{ std::move(logger) }
{}
{
.
event( make_event_handler< req_A >(
"req_A" ) )
.
event( make_event_handler< req_B >(
"req_B" ) )
.
event( make_event_handler< req_C >(
"req_C" ) )
.
event( make_event_handler< req_D >(
"req_D" ) )
.
event( make_event_handler< req_E >(
"req_E" ) )
.
event( make_event_handler< req_F >(
"req_F" ) )
.
event( make_event_handler< req_G >(
"req_G" ) )
.
event( make_event_handler< req_I >(
"req_I" ) )
;
}
};
{
template< typename Request >
[[nodiscard]]
auto make_request_handler(
std::string name,
std::chrono::milliseconds duration )
{
return [this, req_name=std::move(name), duration]
( mhood_t< Request > cmd )
{
"processing request " + req_name + " (" +
std::to_string( cmd->m_id ) + ") for " +
std::to_string( duration.count() ) + "ms" );
std::this_thread::sleep_for(
std::chrono::milliseconds( duration ) );
};
}
public :
a_processor_t(
context_t ctx,
+ limit_then_redirect< req_A >( 10u, trash_can )
+ limit_then_redirect< req_C >( 8u, trash_can )
+ limit_then_redirect< any_unspecified_message >( 4u, trash_can )
}
, m_logger( std::move( logger ) )
{}
{
.
event( make_request_handler< req_A >(
"req_A", 1ms ) )
.
event( make_request_handler< req_B >(
"req_B", 15ms ) )
.
event( make_request_handler< req_C >(
"req_C", 2ms ) )
.
event( make_request_handler< req_D >(
"req_D", 18ms ) )
.
event( make_request_handler< req_E >(
"req_E", 22ms ) )
.
event( make_request_handler< req_F >(
"req_F", 19ms ) )
.
event( make_request_handler< req_G >(
"req_G", 24ms ) )
.
event( make_request_handler< req_I >(
"req_I", 23ms ) )
.
event( [
this]( mhood_t< shutdown > ) {
} )
;
}
};
using sender_t = void(*)(
const so_5::mbox_t & to,
int id );
template< typename Request >
[[nodiscard]]
sender_t make_sender()
{
};
}
{
logger->so_direct_mbox() );
logger->so_direct_mbox(),
trash_can->so_direct_mbox() );
return processor->so_direct_mbox();
});
std::array< sender_t, 10 > senders{
make_sender< req_A >(),
make_sender< req_B >(),
make_sender< req_C >(),
make_sender< req_D >(),
make_sender< req_E >(),
make_sender< req_F >(),
make_sender< req_G >(),
make_sender< req_I >(),
make_sender< req_A >(),
make_sender< req_E >()
};
{
std::random_device rd;
std::mt19937 generator{ rd() };
std::shuffle( std::begin(senders), std::end(senders), generator );
}
int id = 0;
for( int i = 0; i < 15; ++i )
{
for( const auto & s : senders )
s( processor_mbox, id++ );
std::this_thread::sleep_for( 13ms );
}
}
int main()
{
try
{
}
catch( const std::exception & ex )
{
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}
A helper header file for including all public SObjectizer stuff.
virtual void so_define_agent()
Hook on define agent for SObjectizer.
void so_deregister_agent_coop_normally()
A helper method for deregistering agent's coop in case of normal deregistration.
const state_t & so_default_state() const
Access to the agent's default state.
Agent * make_agent_with_binder(so_5::disp_binder_shptr_t binder, Args &&... args)
Helper method for simplification of agents creation and binding to the specified dispatcher.
Agent * make_agent(Args &&... args)
Helper method for simplification of agents creation.
disp_binder_shptr_t binder() const noexcept
Get a binder for that dispatcher.
decltype(auto) introduce_coop(Args &&... args)
Helper method for simplification of cooperation creation and registration.
A base class for agent signals.
const state_t & event(Args &&... args) const
Helper for subscription of event handler in this state.
const int shutdown
Deregistration because SObjectizer Environment shutdown.
SO_5_FUNC dispatcher_handle_t make_dispatcher(environment_t &env, const std::string_view data_sources_name_base, disp_params_t params)
Create an instance of one_thread dispatcher.
Private part of message limit implementation.
void launch(Init_Routine &&init_routine)
Launch a SObjectizer Environment with default parameters.
void send(Target &&to, Args &&... args)
A utility function for creating and delivering a message or a signal.