Closed ilpropheta closed 3 years ago
This is usually done by the following trick:
class busy_agent final : public so_5::agent_t {
struct next_turn final : public so_5::signal_t {};
void on_next_turn(mhood_t<next_turn>) {
... // The loop body is here.
so_5::send<next_turn>(*this); // Initiate the next iteration.
}
...
void so_define_agent() override {
so_subscribe_self().event(&busy_agent::on_next_turn);
}
void so_evt_start() override {
so_5::send<next_turn>(*this);
}
};
Awesome, thanks! Do you think it can make sense to provide an utility agent for this (or in so5Extra)?
I was thinking of something really simple:
class while_true_agent final : public so_5::agent_t
{
struct next_turn final : so_5::signal_t {};
void Step()
{
so_5::send<next_turn>(*this);
}
public:
while_true_agent(context_t c, std::function<void()> action)
: agent_t(std::move(c)), m_action(action)
{
}
void so_define_agent() override
{
so_subscribe_self().event([this](so_5::mhood_t<next_turn>) {
m_action();
Step();
});
}
void so_evt_start() override
{
Step();
}
private:
std::function<void()> m_action;
};
It being understood that std::function
is not a good choice, this is just to give an idea.
I never thought in that direction because such simple agents are very rare in real-life projects. More often they are used in small demos or proof-of-concept experiments where they can be written in minutes from scratch.
Imagine a plain polling like this:
while (true)
{
// this is timed internally (e.g. we want to call "Read" as fast as possible)
auto value = external_service.Read();
// send value somewhere else
//...
}
Do you think agents do not fit such scenarios?
Do you think agents do not fit such scenarios?
My personal point of view: agents work well when you have to deal with different incoming messages in a state. When you have to write something like that:
while(true) {
check_some_condition();
if(case_one_happened()) {...}
check_another_condition();
if(case_two_happened()) {...}
check_yet_another_condition();
if(case_three_happened()) {...}
...
}
then it's a clear marker that you can use some form of message-passing and agents (actors) in particular.
But in such trivial scenarios:
while (true)
{
// this is timed internally (e.g. we want to call "Read" as fast as possible)
auto value = external_service.Read();
// send value somewhere else
//...
}
agents only create additional boilerplate without any benefits.
That is my very subjective IMHO.
Maybe mchains can do what you want.
If get it wright, then you want to equip a casual thread loop with external manipulations. Then it would look somethin like this (didn't compile or check):
so_5::receive( so_5::from( mch ).handle_all(),
[&](so_5::mhood_t<next_iteration>) {
auto value = external_service.Read();
// send value somewhere else
//...
so_5::send<next_iteration>( mch );
},
[&](so_5::mhood_t<adjust_logic >cmd ) {
// Do something that affects main loop logic above
});
// Stop the loop somewhere on the other thread:
so_5::close_drop_content( mch );
That is my very subjective IMHO.
Many thanks for sharing your thoughts. I get your point.
I was trying to understand if SObjectizer can fit that scenario just because it's definitely a simplification to have a single way to manage concurrent objects and to encapsulate behaviors into agents. However, this comes with some trade-offs that must be taken into consideration.
Thanks @ngrodzitski for your snippet. I think @eao197 's solution is enough for my needs ;)
Hi, this is probably a simple question but I am wondering which are your recommended answers.
I need to encapsulate a classical endless loop into a SObjectizer agent. Something like this:
Also, I would like to remove "StopAndWait" and let SObjectizer handle shutdown automatically as it happens normally.
I guess this can be modeled with states. Do you recommend any common implementations?
Many thanks.