DON'T KNOW HOW TO DO THAT!
It is necessary something like this:
so_5::rt::service_proxy_t< int(const msg_convert &) > proxy = mbox->get_one< int >().wait_forever(); proxy.make_sync_get( "1234" );
Instead of:
so_5::rt::infinite_wait_service_invoke_proxy_t< int > proxy = mbox->get_one< int >().wait_forever(); proxy.make_sync_get< msg_convert >( "1234" );
And that service_proxy_t should accept both wait_forever()-created and wait_for()-created proxies.
This kind of lambda does not tested:
[]() mutable { ... }
A new syntax for service invocation:
// Ansyc service call. A std::future is returned. mbox.get_one<ret_type>().async(msg); mbox.get_one<ret_type>().make_async<msg_type>(msg_args); // Sync service call with infinite wail. // A value is returned. mbox.get_one<ret_type>().wait_forever().sync_get(msg); mbox.get_one<ret_type>().wait_forever().make_sync_get<msg_type>(msg_args); // Sync service call with time-limited wail. // A value is returned or exception is thrown. mbox.get_one<ret_type>().wait_for(time).sync_get(msg); mbox.get_one<ret_type>().wait_for(time).make_sync_get<msg_type>(msg_args); // This could be used instead of get_one<void>: mbox.run_one()./* some_action_here... */
Like this:
so_subscribe( mbox ).in( st_1 ).in( st_2 ).in( st_3 ) .event( &my_agent_t::evt_handler );
instead of the current form:
so_subscribe( mbox ).in( st_1 ).event( &my_agent_t::evt_handler ); so_subscribe( mbox ).in( st_2 ).event( &my_agent_t::evt_handler ) so_subscribe( mbox ).in( st_3 ).event( &my_agent_t::evt_handler );
May be it is better to write:
virtual void so_define_agent() { so_subscribe( mbox ).event( &my_agent_t::evt_do_something ); so_subscribe( mbox ).event( so_5::signal< msg_query_status >, &my_agent_t::evt_query_status ); } void evt_do_something( const msg_parameters & ) { ... } std::string evt_query_status() { ... }
Instead of the current form with so_5::rt::event_data_t.
For example:
virtual void so_define_agent() { so_subscribe(mbox).event( so_5::signal< msg_query_status >, []() -> std::string { return m_current_status; } ); so_subscribe(mbox).event( [](const msg_convert & msg) -> int { return std::atoi(msg.m_value); } ); }
SEE [so-5.3.0 Exception reaction inheritance] FOR THE DESCRIPTION
For details about unhandled exception reaction please see [so-5.2.3 Reaction to unhandled exceptions].
There are cases where unhandled exception reaction should be specified not on agent's level, but on cooperation level or event on whole so_environment level. For example in a simple program any exception should lead to program termination. In such case is hard or even impossible to redefine so_exception_reaction for every agent in the program.
The solution could be as follows:
NOTE. May be it is necessary to call so_exception_reaction() for parent cooperation and so on.
SEE [so-5.3.0 New run_so_environment variants] FOR THE DETAILS
There should be a variant of run_so_environment which receives lambda-function or std::function object:
so_5::api::run_so_environment( [](so_5::rt::so_environment_t & env) { env->register_agent_as_coop( "test", new a_test_t( env ) ); } );
There are two variants of schedule_timer/single_timer methods: one for message objects and second for the signals. It is possible to create schedule_timer/single_timer overloads for std::chrono::duration<Rep,Period>. It would lead to templates like that:
template< class M, class R1, class P1, class R2, class P2 > so_5::timer_thread::timer_id_ref_t schedule_timer( std::unique_ptr< M > message, const so_5::rt::mbox_ref_t & mbox, const std::chrono::duration< R1, P1 > & delay, const std::chrono::duration< R2, P2 > & period ) { ... }
But for the case where M -- is a type of signal that overload:
template< class M, class R1, class P1, class R2, class P2 > so_5::timer_thread::timer_id_ref_t schedule_timer( const so_5::rt::mbox_ref_t & mbox, const std::chrono::duration< R1, P1 > & delay, const std::chrono::duration< R2, P2 > & period ) { ... }
Would lead to practical impossibility to use such schedule_timer method because of necessity to write something like this:
so_environment().schedule_timer< my_signal, int, std::milli, int, std::milli >( mbox, std::chrono::millisecond(500), std::chrono::millisecond(250) );
So instead of creating various schedule_timer/single_timer overloads a simple std::chrono::duration to milliseconds helper function is added: so_5::chrono_helpers::to_ms. It allows to write:
so_environment().schedule_timer< my_signal >( mbox, so_5::chrono_helpers::to_ms( std::chrono::minutes(3) ), so_5::chrono_helpers::to_ms( std::chrono::second(45) ) );
THERE IS NO SPEED UP WHEN RAW POINTERS ARE USED
Some time are spent in event-handler invocation routine on the following fragment:
const event_data_t< MESSAGE > event_data( dynamic_cast< MESSAGE * >( message_ref.get() ) );
But if store raw-pointer to message in execution demand together with message_ref it would allow to call event handler without this casting. It is safe because delivery_message() methods receive pointers which are already of type MESSAGE*. Dynamic casting is used because message_ref stores pointer to so_5::rt::message_t and there is no original MESSAGE raw-pointer value.
Wiki: Internals
Wiki: so-5.2.3 Reaction to unhandled exceptions
Wiki: so-5.3.0 Exception reaction inheritance
Wiki: so-5.3.0 New run_so_environment variants