SlideShare a Scribd company logo
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

More Related Content

PDF
Dive into SObjectizer 5.5. Ninth Part: Message Chains
PDF
Dive into SObjectizer 5.5. Fifth part: Timers
PDF
Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction
PDF
Dive into SObjectizer 5.5. Third part. Coops
PDF
Dive into SObjectizer 5.5. Introductory part
PDF
Dive into SObjectizer 5.5. Seventh part: Message Limits
PDF
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
PDF
What is SObjectizer 5.5
Dive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Fifth part: Timers
Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction
Dive into SObjectizer 5.5. Third part. Coops
Dive into SObjectizer 5.5. Introductory part
Dive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
What is SObjectizer 5.5

What's hot (20)

PDF
Dive into SObjectizer 5.5. Fourth part. Exception
PDF
arataga. SObjectizer and RESTinio in action: a real-world example
PDF
Date Processing Attracts Bugs or 77 Defects in Qt 6
PDF
Chain of responsibility
PDF
Miranda NG Project to Get the "Wild Pointers" Award (Part 1)
KEY
What's New In Python 2.6
PDF
PVS-Studio vs Chromium. 3-rd Check
PPTX
Chain of Responsibility Pattern
ODP
Creating a Java EE 7 Websocket Chat Application
PPTX
Android session-5-sajib
ODP
Testing RESTful Webservices using the REST-assured framework
PDF
PDF
Still Comparing "this" Pointer to Null?
PDF
Java Concurrency in Practice
PDF
The Little Unicorn That Could
PPT
Tech talk
PDF
Checking Clang 11 with PVS-Studio
PDF
C# simplified
PPTX
Basic vbscript for qtp
PDF
Analyzing ReactOS One More Time
Dive into SObjectizer 5.5. Fourth part. Exception
arataga. SObjectizer and RESTinio in action: a real-world example
Date Processing Attracts Bugs or 77 Defects in Qt 6
Chain of responsibility
Miranda NG Project to Get the "Wild Pointers" Award (Part 1)
What's New In Python 2.6
PVS-Studio vs Chromium. 3-rd Check
Chain of Responsibility Pattern
Creating a Java EE 7 Websocket Chat Application
Android session-5-sajib
Testing RESTful Webservices using the REST-assured framework
Still Comparing "this" Pointer to Null?
Java Concurrency in Practice
The Little Unicorn That Could
Tech talk
Checking Clang 11 with PVS-Studio
C# simplified
Basic vbscript for qtp
Analyzing ReactOS One More Time
Ad

Similar to Dive into SObjectizer 5.5. Tenth part: Mutable Messages (20)

PDF
What's new in SObjectizer 5.5.9
PDF
What is SObjectizer 5.6 (at v.5.6.0)
PDF
What is SObjectizer 5.7 (at v.5.7.0)
PPTX
20131028 BTUG.be - BizTalk Deployment
PDF
Consequences of using the Copy-Paste method in C++ programming and how to dea...
PDF
Advanced Node.JS Meetup
DOCX
How to build typing indicator in a Chat app
ODP
The power of mysqlnd plugins
ODP
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
DOC
Typescript Basics
ODP
Architecture your android_application
PDF
Microservices in Golang
PDF
Mdb dn 2017_18_query_hackathon
PDF
Embedded c
PPTX
Swift 5.2 what are the new things that you need to know about
PDF
IBM MQ V8 annd JMS 2.0
PPT
IPC mechanisms in windows
PDF
4Developers: Dominik Przybysz- Message Brokers
PPTX
Compose in Theory
PPTX
Typescript language extension of java script
What's new in SObjectizer 5.5.9
What is SObjectizer 5.6 (at v.5.6.0)
What is SObjectizer 5.7 (at v.5.7.0)
20131028 BTUG.be - BizTalk Deployment
Consequences of using the Copy-Paste method in C++ programming and how to dea...
Advanced Node.JS Meetup
How to build typing indicator in a Chat app
The power of mysqlnd plugins
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
Typescript Basics
Architecture your android_application
Microservices in Golang
Mdb dn 2017_18_query_hackathon
Embedded c
Swift 5.2 what are the new things that you need to know about
IBM MQ V8 annd JMS 2.0
IPC mechanisms in windows
4Developers: Dominik Przybysz- Message Brokers
Compose in Theory
Typescript language extension of java script
Ad

More from Yauheni Akhotnikau (14)

PDF
Actor Model and C++: what, why and how? (March 2020 Edition)
PDF
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
PDF
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
PDF
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
PDF
Акторы на C++: стоило ли оно того?
PDF
25 Years of C++ History Flashed in Front of My Eyes
PDF
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
PDF
Actor Model and C++: what, why and how?
PDF
Шишки, набитые за 15 лет использования акторов в C++
PDF
Для чего мы делали свой акторный фреймворк и что из этого вышло?
PDF
Модель акторов и C++ что, зачем и как?
PDF
What’s new in SObjectizer 5.5.8
PDF
Погружение в SObjectizer 5.5. Вводная часть
PDF
Обзор SObjectizer 5.5
Actor Model and C++: what, why and how? (March 2020 Edition)
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы на C++: стоило ли оно того?
25 Years of C++ History Flashed in Front of My Eyes
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
Actor Model and C++: what, why and how?
Шишки, набитые за 15 лет использования акторов в C++
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Модель акторов и C++ что, зачем и как?
What’s new in SObjectizer 5.5.8
Погружение в SObjectizer 5.5. Вводная часть
Обзор SObjectizer 5.5

Recently uploaded (20)

PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Digital Strategies for Manufacturing Companies
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PPTX
Transform Your Business with a Software ERP System
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
L1 - Introduction to python Backend.pptx
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
System and Network Administraation Chapter 3
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
System and Network Administration Chapter 2
Operating system designcfffgfgggggggvggggggggg
Wondershare Filmora 15 Crack With Activation Key [2025
2025 Textile ERP Trends: SAP, Odoo & Oracle
Digital Strategies for Manufacturing Companies
VVF-Customer-Presentation2025-Ver1.9.pptx
How to Migrate SBCGlobal Email to Yahoo Easily
Odoo Companies in India – Driving Business Transformation.pdf
wealthsignaloriginal-com-DS-text-... (1).pdf
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Transform Your Business with a Software ERP System
Reimagine Home Health with the Power of Agentic AI​
Softaken Excel to vCard Converter Software.pdf
Design an Analysis of Algorithms II-SECS-1021-03
CHAPTER 2 - PM Management and IT Context
L1 - Introduction to python Backend.pptx
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Upgrade and Innovation Strategies for SAP ERP Customers
System and Network Administraation Chapter 3
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
System and Network Administration Chapter 2

Dive into SObjectizer 5.5. Tenth part: Mutable Messages

  • 1. Dive into SObjectizer-5.5 SObjectizer Team, May 2017 Tenth Part: Mutable Messages at v.5.5.19
  • 2. 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
  • 4. 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
  • 5. 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
  • 6. Example 1: Big Messages SObjectizer Team, May 2017
  • 7. 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
  • 8. 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
  • 9. 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
  • 10. 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
  • 11. It's obvious that the safe way is a very, very inefficient... SObjectizer Team, May 2017
  • 12. Example 2: Messages With Moveable Data Inside SObjectizer Team, May 2017
  • 13. 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
  • 14. 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
  • 15. There Are Some Workarounds Of Course... SObjectizer Team, May 2017
  • 16. 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
  • 17. 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
  • 18. The Real Solution: Mutable Messages SObjectizer Team, May 2017
  • 19. 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
  • 20. 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
  • 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 messages the examples above can be rewritten that way... SObjectizer Team, May 2017
  • 23. 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
  • 24. 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
  • 25. 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
  • 26. Safety Of Mutable Messages SObjectizer Team, May 2017
  • 27. 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
  • 28. 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
  • 29. 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
  • 30. Immutable And Mutable Message Are Different SObjectizer Team, May 2017
  • 31. 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
  • 32. 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
  • 33. Mutable Messages In Synchronous Interaction SObjectizer Team, May 2017
  • 34. 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
  • 35. But note: mutable service request can be sent only into MPSC-mbox or mchain. SObjectizer Team, May 2017
  • 36. Conversion Into An Immutable Message SObjectizer Team, May 2017
  • 37. 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
  • 38. 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
  • 39. 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
  • 40. Mutable Messages And Timers SObjectizer Team, May 2017
  • 41. 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
  • 42. 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
  • 43. Signals Can't Be Mutable SObjectizer Team, May 2017
  • 44. 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
  • 46. 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
  • 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