I noticed that event subscriptions and event callbacks share a hidden lock, which can cause a deadlock in the following situation:
import time import tango import threading CHANGE_EVENT = tango.EventType.CHANGE_EVENT def callback(event): with monitor: print(event.attr_value.value) monitor = threading.RLock() with monitor: proxy = tango.DeviceProxy('sys/tg_test/1') eid1 = proxy.subscribe_event('double_scalar', CHANGE_EVENT, callback) time.sleep(1.) eid2 = proxy.subscribe_event('State', CHANGE_EVENT, callback) print('OK') raw_input()
If an actual double_scalar
event is generated during time.sleep
, here's what happens:
- the callback thread acquires the hidden lock
- the callback thread waits for the monitor lock
- the main thread wakes up (end of sleep)
- the main thread runs subscribe_event
- the main thread waits for the hidden lock
- deadlock!
This is actually what happens in some devices, when the event callback tries to acquire the monitor lock (useful to prevent race condition between device callbacks and event callbacks).
Weirdly enough, I haven't been able to reproduce it during the first init_device
. Instead, I had to run the INIT
command to run init_device
a second time and reliably generate the deadlock.
Tested with tango 9.2.2.