Dive into SObjectizer-5.5
SObjectizer Team, May 2017
Tenth Part: Mutable Messages
at v.5.5.19
This is the next part of the series of presentations with deep
introduction into features of SObjectizer-5.5.
This part is dedicated to mutable messages.
The feature is very young.
It was introduced in v.5.5.19.
SObjectizer Team, May 2017
Introduction
SObjectizer Team, May 2017
Since the very beginning there were only immutable
messages in SObjectizer-5.
Immutable message is a very simple and safe approach to
implement an interaction in a concurrent application:
● a message instance can be received by any number of
receivers at the same time;
● a message can be redirected to any number of new
receivers;
● a message can be stored to be processed later...
SObjectizer Team, May 2017
Because of that immutable messages are very useful in 1:N
or N:M interactions.
And because Publish-Subscribe Model was the first model
supported by SObjectizer-5 the interaction via immutable
messages is used by default.
But there can be cases when immutable message is not a
good choice in 1:1 interaction...
SObjectizer Team, May 2017
Example 1: Big Messages
SObjectizer Team, May 2017
Let's consider a pipeline of agents which need to modify a
big binary object...
A message like this:
struct raw_image_fragment final : public so_5::message_t {
std::array<std::uint8_t, 10*1024*1024> raw_data_;
...
};
That need to be processed by a pipeline like that...
SObjectizer Team, May 2017
An imaginary pipeline of agents which need to modify the
message:
class first_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
... // Some modification of cmd's contents.
next_stage_->deliver_message(cmd.make_reference()); // Send to the next.
}
...
};
class second_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
... // Some modification of cmd's contents.
next_stage_->deliver_message(cmd.make_reference()); // Send to the next.
}
...
};
SObjectizer Team, May 2017
But... It won't be compiled!
class first_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[0] = ...; // WON'T COMPILE! cmd->raw_data_ is const!
...
next_stage_->deliver_message(cmd.make_reference()); // Send to the next.
}
...
};
class second_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[1] = ...; // WON'T COMPILE! cmd->raw_data_ is const!
...
next_stage_->deliver_message(cmd.make_reference()); // Send to the next.
}
...
};
SObjectizer Team, May 2017
A safe way is copy, modify and send modified copy...
class first_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
auto cp = std::make_unique<raw_image_fragment>(*cmd);
cp->raw_data_[0] = ...;
...
next_stage_->deliver_message(std::move(cp)); // Send to the next.
}
...
};
class second_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
auto cp = std::make_unique<raw_image_fragment>(*cmd);
cp->raw_data_[1] = ...;
...
next_stage_->deliver_message(std::move(cp)); // Send to the next.
}
...
};
SObjectizer Team, May 2017
It's obvious that the safe way is a very, very inefficient...
SObjectizer Team, May 2017
Example 2: Messages With Moveable Data Inside
SObjectizer Team, May 2017
Let's consider a case where agent Alice opens a file and
then transfers opened file to agent Bob:
struct process_file final : public so_5::message_t { // A message to transfer opened file.
std::ifstream file_;
process_file(std::ifstream file) : file_(std::move(file)) {}
};
class Alice final : public so_5::agent_t {
...
void on_handle_file(mhood_t<start_file_processing> cmd) {
std::ifstream file(cmd->file_name()); // Try to open...
if(file) so_5::send<process_file>(bob_mbox, std::move(file)); // Transfer file to Bob.
}
};
class Bob final : public so_5::agent_t {
...
void on_process_file(mhood_t<process_file> cmd) {
... // Some file processing code.
}
};
SObjectizer Team, May 2017
But if we try to do something like that:
class Bob final : public so_5::agent_t {
...
void on_process_file(mhood_t<process_file> cmd) {
std::ifstream file(std::move(cmd->file_)); // (1)
... // Processing file content.
}
};
We will get a compile-time error at point (1) because
cmd->file_ is const and can't be moved anywhere...
SObjectizer Team, May 2017
There Are Some Workarounds Of Course...
SObjectizer Team, May 2017
You can declare fields of your messages as mutable:
struct raw_image_fragment final : public so_5::message_t {
mutable std::array<std::uint8_t, 10*1024*1024> raw_data_;
...
};
class first_modificator final : public so_5::agent_t {
void on_fragment(mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[0] = ...; // Now it works.
...
next_stage_->deliver_message(cmd.make_reference()); // Send to the next.
}
...
};
But what if your message is received by two agents at the
same time? There is no any guarantee that message will be
delivered only to the single receiver...
SObjectizer Team, May 2017
Or you can use shared_ptr instead of object itself:
struct process_file final : public so_5::message_t { // A message to transfer opened file.
std::shared_ptr<std::ifstream> file_;
process_file(std::shared_ptr<std::ifstream> file) : file_(std::move(file)) {}
};
class Alice final : public so_5::agent_t {
...
void on_handle_file(mhood_t<start_file_processing> cmd) {
auto file = std::make_shared<std::ifstream>(cmd->file_name()); // Try to open...
if(*file) so_5::send<process_file>(bob_mbox, std::move(file)); // Transfer file to Bob.
}
};
But there is additional memory allocation and additional level
of data indirection. Overhead can be significant if you need
to transfer small objects like mutexes.
SObjectizer Team, May 2017
The Real Solution: Mutable Messages
SObjectizer Team, May 2017
Since v.5.5.19 a message of type Msg can be sent either as
immutable one:
so_5::send<Msg>(dest, ... /* Msg's constructor args */);
so_5::send_delayed<Msg>(dest, pause, ... /* Msg's constructor args */);
and as mutable one:
so_5::send<so_5::mutable_msg<Msg>>(dest, ... /* Msg's constructor args */);
so_5::send_delayed<so_5::mutable_msg<Msg>>(dest, pause, ... /* Msg's constructor args */);
SObjectizer Team, May 2017
To receive and handle a mutable message an event handler
must have on of the following formats:
result_type handler(so_5::mhood_t<so_5::mutable_msg<Msg>>);
result_type handler(so_5::mutable_mhood_t<Msg>);
SObjectizer Team, May 2017
Note, that mutable_mhood_t<M> is just a shorthand for
mhood_t<mutable_msg<M>>.
Usage of mutable_mhood_t<M> makes code more compact
and concise. But mhood_t<mutable_msg<M>> can be used
in templates:
template<typename M> // Can be Msg or mutable_msg<Msg>
class demo : public so_5::agent_t {
...
void on_message(mhood_t<M> cmd) {
...
}
};
SObjectizer Team, May 2017
With mutable messages the examples above can be
rewritten that way...
SObjectizer Team, May 2017
An example with big messages:
struct raw_image_fragment final : public so_5::message_t {
std::array<std::uint8_t, 10*1024*1024> raw_data_;
...
};
class first_modificator final : public so_5::agent_t {
void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[0] = ...; // Now it works.
...
so_5::send(next_stage_, std::move(cmd)); // Send to the next.
}
...
};
class second_modificator final : public so_5::agent_t {
void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[1] = ...; // Now it works.
...
so_5::send(next_stage_, std::move(cmd)); // Send to the next.
}
...
};
SObjectizer Team, May 2017
An example with moveable object inside:
struct process_file final : public so_5::message_t { // A message to transfer opened file.
std::ifstream file_;
process_file(std::ifstream file) : file_(std::move(file)) {}
};
class Alice final : public so_5::agent_t {
...
void on_handle_file(mhood_t<start_file_processing> cmd) {
std::ifstream file(cmd->file_name()); // Try to open...
if(file) so_5::send<so_5::mutable_msg<process_file>>(bob_mbox, std::move(file)); // Transfer file.
}
};
class Bob final : public so_5::agent_t {
...
void on_process_file(mutable_mhood_t<process_file> cmd) {
std::ifstream file(std::move(cmd->file_)); // Now it works because cmd->file_ is not const.
... // Some file processing code.
}
};
SObjectizer Team, May 2017
But why sending of a mutable message is safer that sending
an immutable message with mutable fields inside?
Are there some guarantees from SObjectizer?
SObjectizer Team, May 2017
Safety Of Mutable Messages
SObjectizer Team, May 2017
A mutable message can be sent only to MPSC mbox or
mchain.
It means that there can be at most one receiver of the
message.
An attempt to send mutable message to MPMC mbox will
lead to an exception at run-time.
SObjectizer Team, May 2017
A mutable_mhood_t<M> works just like std::unique_ptr:
when you redirect your mutable message to someone
else your mutable_mhood_t becomes nullptr.
It means that you lost your access to mutable message after
redirection:
void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) {
cmd->raw_data_[0] = ...; // Now it works.
...
so_5::send(next_stage_, std::move(cmd)); // cmd is a nullptr now!
cmd->raw_data_[0] = ...; // It will lead to access violation or something similar.
}
SObjectizer Team, May 2017
These all mean that only one receiver can have access to
mutable message instance at some time.
This property can't be satisfied for immutable message.
And this makes usage of mutable messages safe.
SObjectizer Team, May 2017
Immutable And Mutable Message Are Different
SObjectizer Team, May 2017
Mutable message of type M has different type than
immutable message of type M.
It means that an agent can have different event handlers for
mutable and immutable M...
SObjectizer Team, May 2017
An example of handling mutable and immutable message of
the same source type M:
class two_handlers final : public so_5::agent_t {
struct M final {};
public :
two_handlers(context_t ctx) : so_5::agent_t(std::move(ctx)) {
so_subscribe_self()
.event(&two_handlers::on_immutable_M)
.event(&two_handlers::on_mutable_M);
}
virtual void so_evt_start() override {
so_5::send<M>(*this); // Immutable message is sent.
so_5::send<so_5::mutable_msg<M>>(*this); // Mutable message is sent.
}
private :
void on_immutable_M(mhood_t<M>) { std::cout << "on immutable" << std::endl; }
void on_mutable_M(mhood_t<so_5::mutable_msg<M>>) { std::cout << "on mutable" << std::endl; }
};
SObjectizer Team, May 2017
Mutable Messages In Synchronous Interaction
SObjectizer Team, May 2017
A mutable message can be used for service requests (e.g.
for synchronous interactions):
class service_provider final : public so_5::agent_t {
public :
service_provider(context_t ctx) : so_5::agent_t(std::move(ctx)) {
// Service request handler.
so_subscribe_self().event([](mutable_mhood_t<std::string> cmd) {
*cmd = "<" + *cmd + ">"; // Modify incoming message.
return std::move(*cmd); // Return modified value.
});
}
...
};
...
so_5::mbox_t provider_mbox = ...; // Must be MPSC mbox or mchain.
auto r = so_5::request_value<std::string, so_5::mutable_msg<std::string>>( // Initiate request.
provider_mbox, so_5::infinite_wait, "hello");
SObjectizer Team, May 2017
But note: mutable service request can be sent only into
MPSC-mbox or mchain.
SObjectizer Team, May 2017
Conversion Into An Immutable Message
SObjectizer Team, May 2017
When a mutable message is received via mutable_mhood_t
and then redirected via send or request_value/future then
redirected message will also be a mutable message. It
means that redirected message can be sent only to one
subscriber and can be handled only via mutable_mhood_t.
Sometimes it is necessary to remove mutability of a
message and send the message as immutable one. It can
be done via to_immutable helper function...
SObjectizer Team, May 2017
Helper function to_immutable converts its argument from
mutable_mhood_t<M> into mhood_t<M> and returns
message hood to immutable message.
This new message hood can be used as parameter for send,
request_value or receive_future. Old mutable message hood
becomes a nullptr and can't be used anymore.
Note: a mutable message can be converted to immutable
message only once. An immutable message can't be
converted into mutable one.
SObjectizer Team, May 2017
An example of usage of to_immutable:
void some_agent::on_some_message(mutable_mhood_t<some_message> cmd) {
... // Some actions with the content of cmd.
// Now the mutable message will be resend as immutable one.
so_5::send(another_mbox, so_5::to_immutable(std::move(cmd)));
// NOTE: cmd is a nullptr now. It can't be used anymore.
...
}
SObjectizer Team, May 2017
Mutable Messages And Timers
SObjectizer Team, May 2017
Mutable messages can be sent by send_delayed functions:
// It is a valid call:
so_5::send_delayed<so_5::mutable_msg<some_message>>(
so_environment(), dest_mbox,
std::chrono::milliseconds(200), // Delay before message appearance.
... // some_message's constructor args.
);
SObjectizer Team, May 2017
Mutable messages can't be sent as periodic messages. It
means that send_periodic can be used with mutable_msg
only if a period parameter is zero:
// It is a valid call:
auto timer = so_5::send_periodic<so_5::mutable_msg<some_message>>(
so_environment(), dest_mbox,
std::chrono::milliseconds(200), // Delay before message appearance.
std::chrono::milliseconds::zero(), // Period is zero.
...);
// It isn't a valid call. An exception will be thrown at run-time.
auto timer = so_5::send_periodic<so_5::mutable_msg<some_message>>(
so_environment(), dest_mbox,
std::chrono::milliseconds(200), // Delay before message appearance.
std::chrono::milliseconds(150), // Period is not zero.
...);
SObjectizer Team, May 2017
Signals Can't Be Mutable
SObjectizer Team, May 2017
Signals do not carry any information inside.
Because of that there is no sense in mutable_msg<S>
where S is a signal type.
Because of that an attempt to use mutable_msg<S> in code
will lead to compile-time error if S is a signal.
SObjectizer Team, May 2017
Some Final Words
SObjectizer Team, May 2017
Mutable messages can be used as a safe way of sending
mutable or moveable data in 1:1 interaction.
But 1:1 interaction sometimes can limit level of concurrency
in your application. Because of that it is better to use
mutable messages only if absolutely necessary.
SObjectizer Team, May 2017
Additional Information:
Project’s home: http://sourceforge.net/projects/sobjectizer
Documentation: http://sourceforge.net/p/sobjectizer/wiki/
Forum: http://sourceforge.net/p/sobjectizer/discussion/
Google-group: https://groups.google.com/forum/#!forum/sobjectizer
Support: https://stiffstream.com

Dive into SObjectizer 5.5. Tenth part: Mutable Messages

  • 1.
    Dive into SObjectizer-5.5 SObjectizerTeam, May 2017 Tenth Part: Mutable Messages at v.5.5.19
  • 2.
    This is thenext part of the series of presentations with deep introduction into features of SObjectizer-5.5. This part is dedicated to mutable messages. The feature is very young. It was introduced in v.5.5.19. SObjectizer Team, May 2017
  • 3.
  • 4.
    Since the verybeginning there were only immutable messages in SObjectizer-5. Immutable message is a very simple and safe approach to implement an interaction in a concurrent application: ● a message instance can be received by any number of receivers at the same time; ● a message can be redirected to any number of new receivers; ● a message can be stored to be processed later... SObjectizer Team, May 2017
  • 5.
    Because of thatimmutable messages are very useful in 1:N or N:M interactions. And because Publish-Subscribe Model was the first model supported by SObjectizer-5 the interaction via immutable messages is used by default. But there can be cases when immutable message is not a good choice in 1:1 interaction... SObjectizer Team, May 2017
  • 6.
    Example 1: BigMessages SObjectizer Team, May 2017
  • 7.
    Let's consider apipeline of agents which need to modify a big binary object... A message like this: struct raw_image_fragment final : public so_5::message_t { std::array<std::uint8_t, 10*1024*1024> raw_data_; ... }; That need to be processed by a pipeline like that... SObjectizer Team, May 2017
  • 8.
    An imaginary pipelineof agents which need to modify the message: class first_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { ... // Some modification of cmd's contents. next_stage_->deliver_message(cmd.make_reference()); // Send to the next. } ... }; class second_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { ... // Some modification of cmd's contents. next_stage_->deliver_message(cmd.make_reference()); // Send to the next. } ... }; SObjectizer Team, May 2017
  • 9.
    But... It won'tbe compiled! class first_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[0] = ...; // WON'T COMPILE! cmd->raw_data_ is const! ... next_stage_->deliver_message(cmd.make_reference()); // Send to the next. } ... }; class second_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[1] = ...; // WON'T COMPILE! cmd->raw_data_ is const! ... next_stage_->deliver_message(cmd.make_reference()); // Send to the next. } ... }; SObjectizer Team, May 2017
  • 10.
    A safe wayis copy, modify and send modified copy... class first_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { auto cp = std::make_unique<raw_image_fragment>(*cmd); cp->raw_data_[0] = ...; ... next_stage_->deliver_message(std::move(cp)); // Send to the next. } ... }; class second_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { auto cp = std::make_unique<raw_image_fragment>(*cmd); cp->raw_data_[1] = ...; ... next_stage_->deliver_message(std::move(cp)); // Send to the next. } ... }; SObjectizer Team, May 2017
  • 11.
    It's obvious thatthe safe way is a very, very inefficient... SObjectizer Team, May 2017
  • 12.
    Example 2: MessagesWith Moveable Data Inside SObjectizer Team, May 2017
  • 13.
    Let's consider acase where agent Alice opens a file and then transfers opened file to agent Bob: struct process_file final : public so_5::message_t { // A message to transfer opened file. std::ifstream file_; process_file(std::ifstream file) : file_(std::move(file)) {} }; class Alice final : public so_5::agent_t { ... void on_handle_file(mhood_t<start_file_processing> cmd) { std::ifstream file(cmd->file_name()); // Try to open... if(file) so_5::send<process_file>(bob_mbox, std::move(file)); // Transfer file to Bob. } }; class Bob final : public so_5::agent_t { ... void on_process_file(mhood_t<process_file> cmd) { ... // Some file processing code. } }; SObjectizer Team, May 2017
  • 14.
    But if wetry to do something like that: class Bob final : public so_5::agent_t { ... void on_process_file(mhood_t<process_file> cmd) { std::ifstream file(std::move(cmd->file_)); // (1) ... // Processing file content. } }; We will get a compile-time error at point (1) because cmd->file_ is const and can't be moved anywhere... SObjectizer Team, May 2017
  • 15.
    There Are SomeWorkarounds Of Course... SObjectizer Team, May 2017
  • 16.
    You can declarefields of your messages as mutable: struct raw_image_fragment final : public so_5::message_t { mutable std::array<std::uint8_t, 10*1024*1024> raw_data_; ... }; class first_modificator final : public so_5::agent_t { void on_fragment(mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[0] = ...; // Now it works. ... next_stage_->deliver_message(cmd.make_reference()); // Send to the next. } ... }; But what if your message is received by two agents at the same time? There is no any guarantee that message will be delivered only to the single receiver... SObjectizer Team, May 2017
  • 17.
    Or you canuse shared_ptr instead of object itself: struct process_file final : public so_5::message_t { // A message to transfer opened file. std::shared_ptr<std::ifstream> file_; process_file(std::shared_ptr<std::ifstream> file) : file_(std::move(file)) {} }; class Alice final : public so_5::agent_t { ... void on_handle_file(mhood_t<start_file_processing> cmd) { auto file = std::make_shared<std::ifstream>(cmd->file_name()); // Try to open... if(*file) so_5::send<process_file>(bob_mbox, std::move(file)); // Transfer file to Bob. } }; But there is additional memory allocation and additional level of data indirection. Overhead can be significant if you need to transfer small objects like mutexes. SObjectizer Team, May 2017
  • 18.
    The Real Solution:Mutable Messages SObjectizer Team, May 2017
  • 19.
    Since v.5.5.19 amessage of type Msg can be sent either as immutable one: so_5::send<Msg>(dest, ... /* Msg's constructor args */); so_5::send_delayed<Msg>(dest, pause, ... /* Msg's constructor args */); and as mutable one: so_5::send<so_5::mutable_msg<Msg>>(dest, ... /* Msg's constructor args */); so_5::send_delayed<so_5::mutable_msg<Msg>>(dest, pause, ... /* Msg's constructor args */); SObjectizer Team, May 2017
  • 20.
    To receive andhandle a mutable message an event handler must have on of the following formats: result_type handler(so_5::mhood_t<so_5::mutable_msg<Msg>>); result_type handler(so_5::mutable_mhood_t<Msg>); SObjectizer Team, May 2017
  • 21.
    Note, that mutable_mhood_t<M>is just a shorthand for mhood_t<mutable_msg<M>>. Usage of mutable_mhood_t<M> makes code more compact and concise. But mhood_t<mutable_msg<M>> can be used in templates: template<typename M> // Can be Msg or mutable_msg<Msg> class demo : public so_5::agent_t { ... void on_message(mhood_t<M> cmd) { ... } }; SObjectizer Team, May 2017
  • 22.
    With mutable messagesthe examples above can be rewritten that way... SObjectizer Team, May 2017
  • 23.
    An example withbig messages: struct raw_image_fragment final : public so_5::message_t { std::array<std::uint8_t, 10*1024*1024> raw_data_; ... }; class first_modificator final : public so_5::agent_t { void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[0] = ...; // Now it works. ... so_5::send(next_stage_, std::move(cmd)); // Send to the next. } ... }; class second_modificator final : public so_5::agent_t { void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[1] = ...; // Now it works. ... so_5::send(next_stage_, std::move(cmd)); // Send to the next. } ... }; SObjectizer Team, May 2017
  • 24.
    An example withmoveable object inside: struct process_file final : public so_5::message_t { // A message to transfer opened file. std::ifstream file_; process_file(std::ifstream file) : file_(std::move(file)) {} }; class Alice final : public so_5::agent_t { ... void on_handle_file(mhood_t<start_file_processing> cmd) { std::ifstream file(cmd->file_name()); // Try to open... if(file) so_5::send<so_5::mutable_msg<process_file>>(bob_mbox, std::move(file)); // Transfer file. } }; class Bob final : public so_5::agent_t { ... void on_process_file(mutable_mhood_t<process_file> cmd) { std::ifstream file(std::move(cmd->file_)); // Now it works because cmd->file_ is not const. ... // Some file processing code. } }; SObjectizer Team, May 2017
  • 25.
    But why sendingof a mutable message is safer that sending an immutable message with mutable fields inside? Are there some guarantees from SObjectizer? SObjectizer Team, May 2017
  • 26.
    Safety Of MutableMessages SObjectizer Team, May 2017
  • 27.
    A mutable messagecan be sent only to MPSC mbox or mchain. It means that there can be at most one receiver of the message. An attempt to send mutable message to MPMC mbox will lead to an exception at run-time. SObjectizer Team, May 2017
  • 28.
    A mutable_mhood_t<M> worksjust like std::unique_ptr: when you redirect your mutable message to someone else your mutable_mhood_t becomes nullptr. It means that you lost your access to mutable message after redirection: void on_fragment(mutable_mhood_t<raw_image_fragment> cmd) { cmd->raw_data_[0] = ...; // Now it works. ... so_5::send(next_stage_, std::move(cmd)); // cmd is a nullptr now! cmd->raw_data_[0] = ...; // It will lead to access violation or something similar. } SObjectizer Team, May 2017
  • 29.
    These all meanthat only one receiver can have access to mutable message instance at some time. This property can't be satisfied for immutable message. And this makes usage of mutable messages safe. SObjectizer Team, May 2017
  • 30.
    Immutable And MutableMessage Are Different SObjectizer Team, May 2017
  • 31.
    Mutable message oftype M has different type than immutable message of type M. It means that an agent can have different event handlers for mutable and immutable M... SObjectizer Team, May 2017
  • 32.
    An example ofhandling mutable and immutable message of the same source type M: class two_handlers final : public so_5::agent_t { struct M final {}; public : two_handlers(context_t ctx) : so_5::agent_t(std::move(ctx)) { so_subscribe_self() .event(&two_handlers::on_immutable_M) .event(&two_handlers::on_mutable_M); } virtual void so_evt_start() override { so_5::send<M>(*this); // Immutable message is sent. so_5::send<so_5::mutable_msg<M>>(*this); // Mutable message is sent. } private : void on_immutable_M(mhood_t<M>) { std::cout << "on immutable" << std::endl; } void on_mutable_M(mhood_t<so_5::mutable_msg<M>>) { std::cout << "on mutable" << std::endl; } }; SObjectizer Team, May 2017
  • 33.
    Mutable Messages InSynchronous Interaction SObjectizer Team, May 2017
  • 34.
    A mutable messagecan be used for service requests (e.g. for synchronous interactions): class service_provider final : public so_5::agent_t { public : service_provider(context_t ctx) : so_5::agent_t(std::move(ctx)) { // Service request handler. so_subscribe_self().event([](mutable_mhood_t<std::string> cmd) { *cmd = "<" + *cmd + ">"; // Modify incoming message. return std::move(*cmd); // Return modified value. }); } ... }; ... so_5::mbox_t provider_mbox = ...; // Must be MPSC mbox or mchain. auto r = so_5::request_value<std::string, so_5::mutable_msg<std::string>>( // Initiate request. provider_mbox, so_5::infinite_wait, "hello"); SObjectizer Team, May 2017
  • 35.
    But note: mutableservice request can be sent only into MPSC-mbox or mchain. SObjectizer Team, May 2017
  • 36.
    Conversion Into AnImmutable Message SObjectizer Team, May 2017
  • 37.
    When a mutablemessage is received via mutable_mhood_t and then redirected via send or request_value/future then redirected message will also be a mutable message. It means that redirected message can be sent only to one subscriber and can be handled only via mutable_mhood_t. Sometimes it is necessary to remove mutability of a message and send the message as immutable one. It can be done via to_immutable helper function... SObjectizer Team, May 2017
  • 38.
    Helper function to_immutableconverts its argument from mutable_mhood_t<M> into mhood_t<M> and returns message hood to immutable message. This new message hood can be used as parameter for send, request_value or receive_future. Old mutable message hood becomes a nullptr and can't be used anymore. Note: a mutable message can be converted to immutable message only once. An immutable message can't be converted into mutable one. SObjectizer Team, May 2017
  • 39.
    An example ofusage of to_immutable: void some_agent::on_some_message(mutable_mhood_t<some_message> cmd) { ... // Some actions with the content of cmd. // Now the mutable message will be resend as immutable one. so_5::send(another_mbox, so_5::to_immutable(std::move(cmd))); // NOTE: cmd is a nullptr now. It can't be used anymore. ... } SObjectizer Team, May 2017
  • 40.
    Mutable Messages AndTimers SObjectizer Team, May 2017
  • 41.
    Mutable messages canbe sent by send_delayed functions: // It is a valid call: so_5::send_delayed<so_5::mutable_msg<some_message>>( so_environment(), dest_mbox, std::chrono::milliseconds(200), // Delay before message appearance. ... // some_message's constructor args. ); SObjectizer Team, May 2017
  • 42.
    Mutable messages can'tbe sent as periodic messages. It means that send_periodic can be used with mutable_msg only if a period parameter is zero: // It is a valid call: auto timer = so_5::send_periodic<so_5::mutable_msg<some_message>>( so_environment(), dest_mbox, std::chrono::milliseconds(200), // Delay before message appearance. std::chrono::milliseconds::zero(), // Period is zero. ...); // It isn't a valid call. An exception will be thrown at run-time. auto timer = so_5::send_periodic<so_5::mutable_msg<some_message>>( so_environment(), dest_mbox, std::chrono::milliseconds(200), // Delay before message appearance. std::chrono::milliseconds(150), // Period is not zero. ...); SObjectizer Team, May 2017
  • 43.
    Signals Can't BeMutable SObjectizer Team, May 2017
  • 44.
    Signals do notcarry any information inside. Because of that there is no sense in mutable_msg<S> where S is a signal type. Because of that an attempt to use mutable_msg<S> in code will lead to compile-time error if S is a signal. SObjectizer Team, May 2017
  • 45.
  • 46.
    Mutable messages canbe used as a safe way of sending mutable or moveable data in 1:1 interaction. But 1:1 interaction sometimes can limit level of concurrency in your application. Because of that it is better to use mutable messages only if absolutely necessary. SObjectizer Team, May 2017
  • 47.
    Additional Information: Project’s home:http://sourceforge.net/projects/sobjectizer Documentation: http://sourceforge.net/p/sobjectizer/wiki/ Forum: http://sourceforge.net/p/sobjectizer/discussion/ Google-group: https://groups.google.com/forum/#!forum/sobjectizer Support: https://stiffstream.com