1 /*
2  * An example of use wrapped_env with simple_mtsafe environment
3  * and two working threads with mchains and delayed messages.
4  */
5 
6 #include <so_5/all.hpp>
7 
8 // Messages for exchanges between threads.
9 struct tick final : public so_5::signal_t {};
10 struct tack final : public so_5::signal_t {};
11 
12 // Special signal to stop the exchange.
13 struct stop final : public so_5::signal_t {};
14 
15 // Helper class for removing code duplication in handling the state of one
16 // working thread.
17 class thread_state final
18 {
19 	std::chrono::milliseconds pause_{ 750 };
20 	bool must_stop_{ false };
21 
22 public :
must_stop() const23 	bool must_stop() const { return must_stop_; }
24 
25 	template<typename Reply>
reply_or_stop(const so_5::mchain_t & to)26 	void reply_or_stop( const so_5::mchain_t & to )
27 	{
28 		if( pause_ > std::chrono::milliseconds(5) )
29 		{
30 			pause_ = std::chrono::milliseconds(
31 					static_cast< decltype(pause_.count()) >(
32 							double(pause_.count()) / 1.5) );
33 			so_5::send_delayed< Reply >( to, pause_ );
34 		}
35 		else
36 		{
37 			so_5::send< stop >( to );
38 			must_stop_ = true;
39 		}
40 	}
41 };
42 
43 // Body for thread.
thread_body(so_5::mchain_t recv_chain,so_5::mchain_t write_chain)44 void thread_body( so_5::mchain_t recv_chain, so_5::mchain_t write_chain )
45 {
46 	thread_state state;
47 	receive(
48 		from(recv_chain).handle_all().stop_on( [&state]{ return state.must_stop(); } ),
49 		[&]( so_5::mhood_t<tick> ) {
50 			std::cout << "Tick!" << std::endl;
51 			state.reply_or_stop< tack >( write_chain );
52 		},
53 		[&]( so_5::mhood_t<tack> ) {
54 			std::cout << "Tack!" << std::endl;
55 			state.reply_or_stop< tick >( write_chain );
56 		} );
57 }
58 
59 // Just a helper function for preparation of environment params.
60 // It is needed just for shortening of main() function code.
make_env_params()61 so_5::environment_params_t make_env_params()
62 {
63 	so_5::environment_params_t env_params;
64 	env_params.infrastructure_factory(
65 			so_5::env_infrastructures::simple_mtsafe::factory() );
66 	return env_params;
67 }
68 
main()69 int main()
70 {
71 	so_5::wrapped_env_t sobj( make_env_params() );
72 
73 	// An instance for second working thread.
74 	// The thread itself will be started later.
75 	std::thread second_thread;
76 	// This thread must be joined later.
77 	const auto thread_joiner = so_5::auto_join( second_thread );
78 
79 	// We need two simple mchains for exchange.
80 	auto ch1 = create_mchain( sobj );
81 	auto ch2 = create_mchain( sobj );
82 	// The chains must be closed automatically.
83 	const auto ch_closer = so_5::auto_close_drop_content( ch1, ch2 );
84 
85 	// Launch another thread.
86 	second_thread = std::thread( thread_body, ch2, ch1 );
87 
88 	// The first message must be initiated.
89 	so_5::send< tick >( ch1 );
90 
91 	// Launch the interchange on the context of main thread.
92 	thread_body( ch1, ch2 );
93 
94 	return 0;
95 }
96 
97