SObjectizer
5.5
|
From the very first version of SObjectizer-5 all messages inside a SObjectizer-application were immutable. There was no possibility to receve a message via non-const reference. Because of that all event handlers had one of the following formats:
The main reason for immutability was the way of message distribution: there was only one type of mbox in the first version of SObjectizer-5 – multi-producer/multi-consumer one. It means that when a message has been sent to such mbox there can be several subscribers which can receive that message at the same time on the context of different work threads.
Immutability of messages is a very good thing in 1:N or N:M interaction. In such cases you can't know how many receivers will handle your message. You also can't know will some receiver redirect your message or store it to process later. Immutability of messages makes such complex scenarios possible.
But there can be cases where only 1:1 interaction is necessary. For example if agents work as a pipeline: a message goes from one agent to another and there is only one receiver for the message. In some of such cases immutability can create difficulties if a message passing through a pipeline must be modified. It can be a very big message and it is not efficient to create a modifyable copy of it for every agent in the pipeline.
If all messages are immutable the only way to pass mutable value inside a message is usage of mutable
keyword. For example, something like:
But this is a very dangerous approach because there is no a guarantee that the message sent will be received and processed only by one receiver. When you call send
function like this:
you can pass MPMC mbox as next_stage_mbox
and your message can be received by several receivers at the same time. It would lead to errors which are very hard to detect and repair.
Since v.5.5.19 there is a real solution for such problem in SObjectizer: there are immutable messages and mutable ones. Immutable messages can be used like in previous SObjectizer's versions (moreover: all messages are still immutable by default). But there is a possibility to send a mutable message. And SObjectizer guarantees that mutable message can be sent only to the single subscriber. Thus mutable message can't be sent into MPMC mbox. Only MPSC mboxes and mchains can be used as the destination to a mutable message.
Mutable message can be redirected to another MPSC mbox or mchain. In this case mutable message behaves just like unique_ptr: you can pass it to someone else but you lose your pointer to it.
Mutable message can be converted to immutable message. But once mutable message lost its mutability and became immutable the mutability can't be returned back.
A message of type M can be sent as immutable message as well as mutable one. To send an instance of M as mutable message the special type wrapper mutable_msg
must be used:
There is also another type wrapper immutable_msg
which can be used for sending of immutable messages:
Please note that in send<mutable_msg<T>>(dest,...)
the dest
must be a MPSC mbox or mchain. Otherwise the exception will be thrown:
To receive a mutable message an event handler must have the following format:
or
where M
is a message type. For example:
Note that an agent can have different event handlers for immutable and mutable message of the same type. For example:
A mutable message can be used for service requests (e.g. for synchronous interactions). For example:
Note that service request with mutable message can't be sent into MPMC mbox: only MPSC mboxes or mchains can be used for request_value
and request_future
with mutable messages as request's parameter.
When mutable messages are used for interaction of agents in a pipeline then there is a need for redirection of the same message object to the next agent in the pipeline. Special versions of send
functions must be used for this task:
There are two things which must be mentioned:
send(dest,...)
is used instead of send<M>(dest,...)
. Type of redirected message is infered automatically;mutable_mhood_t<M>
is moved into send
. The source message hood object becomes a nullptr and can't be used anymore. In this case mutable message hood works like std::unique_ptr
.Functions request_value
and request_future
also have new overloads and accept message hood as a parameter. It means that received message can be redirected as service request. For example:
Please note that 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. For example:
Helper function to_immutable
converts its argument from mhood_t<mutable_msg<M>>
into mhood_t<immutable_msg<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.
Signals can't be sent nor received as mutable. It means that an attempt to write something like:
will lead to compile-time errors because mutable_msg
can't be used with signals.
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. For example:
Helper function so_5::send_delayed
can be used for sending delayed mutable message (but destination must be MPSC mbox or mchain as usual for mutable messages).