Mchains allow to use SObjectizer for writing concurrent programms even without agents. Just mchains and raw std::threads. But usage of std::thread requires some attention becase if std::thread is started as joinable thread it must be joined.
Lets see a simple case where two thread will read and process messages from a mchain:
{
receive(from(ch), handler1, handler2, ...);
}
{
auto ch = create_mchain(env);
thread first_thread{worker_thread, ch};
thread second_thread{worker_thread, ch};
while(has_some_work())
send<do_task>(ch, ...);
}
Private part of message limit implementation.
void close_retain_content(Exceptions_Control exceptions_control, const mchain_t &ch) noexcept(noexcept(details::should_terminate_if_throws_t< Exceptions_Control >::value))
Helper function for closing a message chain with retaining all its content.
This sample has serious errors. Threads must be joined. But simple modification like:
...
while(has_some_work())
send<do_task>(ch, ...);
close_retain_content(ch);
second_thread.join();
first_thread.join();
is not enough. Because the resulting code is not exception safe. To make it exception safe we need to do some additional work:
class auto_joiner {
thread & thr_;
public :
auto_joiner(thread & thr) : thr_{thr} {}
~auto_joiner() {
if(thr_.joinable())
thr_.join();
}
};
...
{
thread first_thread, second_thread;
auto_joiner first_joiner{first_thread}, second_joiner{second_thread};
first_thread = thread{worker_thread, ch};
second_thread = thread{worker_thread, ch};
while(has_some_work())
send<do_task>(ch, ...);
}
mchain_t create_mchain(environment_t &env)
Create size-unlimited chain.
mchain_auto_close_details::auto_closer_t< sizeof...(Tail) > auto_close_retain_content(Tail &&... tail)
Helper function for automatic closing of mchains with retaining their content.
Now sample function is exception safe. It closes mchain automatically and joins all threads automatically.
But it requires addtional class auto_joiner and implementation of that class is not as simple as it seems. If you write such class the first time you probably forget to check thr_.joinable() condition. And your auto_joiner class will crash your application if thread is not started yet.
To make things simpler v.5.5.16 add helper function so_5::auto_join. This function allows to rewrite sample such way:
{
thread first_thread, second_thread;
auto thr_joiner = auto_join(first_thread, second_thread);
auto ch = create_mchain(env);
auto ch_closer = auto_close_retain_content(ch);
first_thread = thread{worker_thread, ch};
second_thread = thread{worker_thread, ch};
while(has_some_work())
send<do_task>(ch, ...);
}