Well, I’m sorry, but when all I receive is a
IROMessage instance, I do not know which class implements the interface, and as such I have no knowledge of the other interfaces it may implement.
Granted, in the SDK, there are no message classes that do not inherit from
TROMessage but there is no guarantee this will stay forever. It’s the basic principle behind using interfaces, one should only work with what the interface provides and not make any assumptions about the underlying class.
Now, if that property was to be changed to
IROMessageCloneable, then that would be an all different story. Even better, I would also make
IROMessageCloneable inherit from
IROMessage so that pretty much any variable of type
IROMessage could be replaced by
IROMessageCloneable, avoiding the use of the
as operator in many places. Obviously, the
Clone method would also return a
Well, yes, if I am to use the event writer in only one thread at at time. To illustrate, here is the situation:
Client1 -> EventSinkWriter1 -> MessageClone1
Client2 -> EventSinkWriter2 -> MessageClone2
Client3 -> EventSinkWriter3 -> MessageClone3
ClientN -> EventSinkWriterN -> MessageCloneN
As already discussed, each event sink has its clone of the original message. So if I have multiple threads each working with a single client, there is no issue whatsoever.
But if I have many threads all calling the same event sink, then there are multiple crashes, as can be seen in this sample application: ROMultithreadedEvents.zip (121.8 KB)
After having compiled the client and server application, debug the server and start the client application on the side.
Classic event storm. This gives 51 events, arriving out of order as expected with events.
But, if you now click on
Parallel event storm, then the server creates multiple threads that all call
TClient.NotifySomethingHappened at the same time, which leads to parallel usage of the message clone held by the
FEventSinkWriter instance inside
And there, you will see crashes all over the place because the calls are stepping on each others toes.
Now, if inside
TMyClientEventSink_Writer.SomethingHappened we make sure that
lMessage is a unique instance, then we have no parallel issue. And one way to make this happen is to change the
_GetMessage method as suggested above. However, this prevents the client from processing the events as it, too, uses
TROEventReceiver. So the real solution is to change the code inside
TMyClientEventSink_Writer.SomethingHappened so that
__Message.Clone but this has one drawback: the changes has to be done again after each regeneration of the Invk file. Hopefully in my case, this does not happen that often.
So, to sum up, I believe the fix requires the generator for events invocations to be changed to make sure
__Message.Clone. And to make this easier, here are the steps that I’m suggesting ( patch file):
IROMessageCloneable so that it inherits from
IROMessageCloneable.Clone so that it returns
TROMessage.Clone to return
IROMessageCloneable (simply change the type and remove the
IROMessageCloneable instead of
TROEventWriter.Create to the above change
TROEventInvoker.Create to the above change
TROEventReceiver.FireEvents, change the type of the
messageclone variable to
And after those changes are in, I believe a review is in order to change quite a few
IROMessage references to
IROMessageCloneable so as to avoid the costly
as operator calls. In particular those that are placed in locations that can be called quite often.