thread safe of Tango::CallBack method
In [Tango::CallBack Class Reference](https://tango-controls.gitlab.io/cppTango/classTango_1_1CallBack.html)
> When using the event push model (callback automatically executed), there are some cases (same callback used for events coming from different devices hosted in device server process running on different hosts) where the callback method could be executed concurently by different threads started by the ORB. The user has to code his callback method in a thread safe manner.
Say that the thread safe of `Tango::CallBack` is needed when same callback used for events coming from different devices hosted in device server process running on different hosts.
But as source codes show, in event push-push model, client only created two Tango event system related threads: the `EventConsumerKeepAliveThread` and the `ZmqEventConsumer` thread (derived from `omni_thread`)
- `ZmqEventConsumer` (a singleton class)
- `ZmqEventConsumer` has an static member object of `EventConsumerKeepAliveThread`
The above two threads may call `CallBack::push_event()` method of same callback, so i think may be this is the reason for thread safety of `Tango::CallBack`, not relating to events source.
I missed something?
I am not sure the documentation is fully up to date and precise on this point but I will try to describe a use case where concurrency might happen.
Please note that the callback can also be called during the subscription process.
When DeviceProxy::subscribe_event() is called, the subscribed attribute is read with a read_attribute() and the result of this synchronous read_attribute call is stored in an EventData object. The callback push_event() is then invoked with this EventData object.
If your client already subscribed to other attributes using the same callback, this callback could be called in parallel if some events are received.
As you correctly pointed out, the 2 threads you mention can also be in concurrency.
Let's consider the following use case: your client subscribed to Attribute1 on Device1 exported by Device Server DS1/1 and subscribed to Attribute2 on Device2 exported by Device Server DS2/2 using the same callback.
If DS1/1 device server is temporarily stopped, after about 10 seconds, the EventConsumerKeepAliveThread will detect that DS1/1 is no longer responding and will invoke the callback push_event for the Attribute1 on Device1 with an Error event, and then will try to reconnect, using a synchronous read_attribute call like during the first subscription. The callback is then invoked again with the result of this read_attribute call.
At the same time, another event coming for Attribute2 from Device2 could be received by the ZmqEventConsumer thread and the same callback could be invoked in parallel.
Hoping this helps a bit.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.