Re: [boost] [msm] Message queue and copy constructed events

Hi Richard,
Lets separate 2 thinks.
1: no heap operation this is a nice to have feature we can live with it. According my understanding the only place where heap is used is in the std:queue ? Am I correct ? If yes than if the user has a possibility to provide its own queue implementation than he/she can make sure about avoiding heap usage.
In the queue AND in the boost::function objects contained in the queue. So merely changing the container will not be sufficient to eliminate all heap usage (read further on).
2: event copying. You saying copy is happening when bind is used to anonymize events to be able to store them in a queue. According my understanding of event driven systems we can say that as log an RTC step is not finished -> means that the most outer process_event does not retuned the event which was used in the call of the process_event should be valid. This means that events will be valid even with queuing for queues which are used during pseudo entry and exit because the processing of those events are always finished before the more outer process_event is returned. The only place where this is not true ->when the event should be available longer than the RTC step is when the event is deferred. So I think it would be enough for non deferred queues to internally before the bind store the event in a ref/cref and bind that and put to the queue -> no copy.
This is incorrect. You can have the same behaviour with the event queue. Consider test/SimpleWithFunctors.cpp: You have a transition: Row < Empty , cd_detected , Stopped , store_cd_info , ... > And in the action, we generate another event: struct store_cd_info { template <class EVT,class FSM,class SourceState,class TargetState> void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& ) { fsm.process_event(play()); // temporary play will be queued, then the function returns // ooops, temporary is gone } /// end of action, transition now ends and will start examining the queue and will find inside a reference to a destroyed event }; Now, if msm was using ref/cref, we would be processing a destroyed event, which would not end well ;-) Unfortunately, it is not possible for process_event to know if the event object is a temporary, therefore the copy. The only way to change this would be to have the user tell msm about it and take responsibility for ensuring event validity. We could: - have an extra parameter to process_event (run-time cost for all users) - allow some compile-time flag (compile-time cost for all users) None is very appealing to me as I doubt many will require this, especially as I fail to see why you could not pimpl the event data, thus making the event cheap to copy. But everybody would have to pay for it somehow. And the heap issue would still be unsolved. This would likely also end at the very bottom of my feature list. I think a possible solution would be the fact that I intend to offer customization of the queue container, which is a much more popular feature. Instead of calling push on it with the boost::function object, I could call push(event), so that you can provide a container not of function objects but of anything (like of a pointers to some base event type or void* if you prefer to cast a little, which I prefer not knowing of ;-) ). This allows complete removal of any heap usage AND could also be used to get rid of event copying (in this case though, you are taking responsibility of having thought of the event objects' lifetime). The downside is that providing a new container will require slightly more work.
For deferred queues there is 2 ways to go. First is to copy the event during bind or have a user implement a queue which interacts whit the underlaying zero copy scheduler. and only again store a ref/cref in a bind. maybe it is enough to have 2 callback to the user when an event is deferred and when it is recalled and not needed any more.
Fore the deferred queue, I can provide the same mechanism, so that you have have different containers for both if you wish. Using boost.parameter will make these extra template arguments more bearable. Regards, Christophe

On 22 June 2010 11:47, Christophe Henry <christophe.j.henry@googlemail.com> wrote:
Hi Richard,
Lets separate 2 thinks.
1: no heap operation this is a nice to have feature we can live with it. According my understanding the only place where heap is used is in the std:queue ? Am I correct ? If yes than if the user has a possibility to provide its own queue implementation than he/she can make sure about avoiding heap usage.
In the queue AND in the boost::function objects contained in the queue. So merely changing the container will not be sufficient to eliminate all heap usage (read further on).
2: event copying. You saying copy is happening when bind is used to anonymize events to be able to store them in a queue. According my understanding of event driven systems we can say that as log an RTC step is not finished -> means that the most outer process_event does not retuned the event which was used in the call of the process_event should be valid. This means that events will be valid even with queuing for queues which are used during pseudo entry and exit because the processing of those events are always finished before the more outer process_event is returned. >The only place where this is not true ->when the event should be available longer than the RTC step is when the event is deferred. So I think it would be enough for non deferred queues to internally before the bind store the event in a ref/cref and bind that and put to the queue -> no copy.
This is incorrect. You can have the same behaviour with the event queue. Consider test/SimpleWithFunctors.cpp: You have a transition: Row < Empty , cd_detected , Stopped , store_cd_info , ... >
And in the action, we generate another event:
struct store_cd_info { template <class EVT,class FSM,class SourceState,class TargetState> void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& ) { fsm.process_event(play()); // temporary play will be queued, then the function returns // ooops, temporary is gone } /// end of action, transition now ends and will start examining the queue and will find inside a reference to a destroyed event };
Now, if msm was using ref/cref, we would be processing a destroyed event, which would not end well ;-)
Unfortunately, it is not possible for process_event to know if the event object is a temporary, therefore the copy. The only way to change this would be to have the user tell msm about it and take responsibility for ensuring event validity. We could: - have an extra parameter to process_event (run-time cost for all users) - allow some compile-time flag (compile-time cost for all users)
None is very appealing to me as I doubt many will require this, especially as I fail to see why you could not pimpl the event data, thus making the event cheap to copy. But everybody would have to pay for it somehow. And the heap issue would still be unsolved. This would likely also end at the very bottom of my feature list.
I think a possible solution would be the fact that I intend to offer customization of the queue container, which is a much more popular feature. Instead of calling push on it with the boost::function object, I could call push(event), so that you can provide a container not of function objects but of anything (like of a pointers to some base event type or void* if you prefer to cast a little, which I prefer not knowing of ;-) ). This allows complete removal of any heap usage AND could also be used to get rid of event copying (in this case though, you are taking responsibility of having thought of the event objects' lifetime). The downside is that providing a new container will require slightly more work.
Thanks for the example all make sense. push with an event and a recall would be sufficient for us. That we can integrate with our non copy event queues and event factories.
For deferred queues there is 2 ways to go. First is to copy the event during bind or have a user implement a queue which interacts whit the underlaying zero copy scheduler. and only again store a ref/cref in a bind. maybe it is enough to have 2 callback to the user when an event is deferred and when it is recalled and not needed any more.
Fore the deferred queue, I can provide the same mechanism, so that you have have different containers for both if you wish. Using boost.parameter will make these extra template arguments more bearable.
It can be a different definition as the normal event queue and if it is the same handling as normal event queue than the user can put the same underlying implementation.
Regards,
Christophe _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (2)
-
Christophe Henry
-
Richard Szabo