tango-controls/pytango

Deadlock when calling subscribe_event ATTR_CONF_EVENT

Closed this issue · 8 comments

Hi,

I am trying to solve a problem on an old library using PyTango with gevent and ATTR_CONF_EVENT subscribtion.

It was working before in 2014, and do not work since a port to a conda environment (then new pytango version, new tango version, new gevent, python 2.6 to python 2.7...)

It looks like, in my library context, the subscribtion to ATTR_CONF_EVENT locks while the one to CHANGE_EVENT returns.

I still have to dig inside the problem, but do you have any idea if this 2 events behave in a different way? And if there was any changes relative to them (since 2014... ^__^) ?

I am using conda with Python 2.7

pytango                   9.3.1            py27ha8d69ae_1    tango-controls
tango                     9.3.2                h6bb024c_0    tango-controls
gevent                    1.2.2            py27h475ea6a_0  

Looks like there is no difference between ATTR_CONF and CHANGE events. Was just un/luck with the timing. Then i think the problem is not there.

It looks like the deadlock occur when i create the device proxy from a thread and when i call the subscription from a greenlet.

Is there a difference if i create a device proxy from a thread or from a greenlet?

Here is how to test.

Test 1 and 2 work well, test 3 deadlock.

Any idea if it is normal?

import gevent
import logging
import PyTango
from PyTango.gevent import DeviceProxy
import threading

logger = logging.getLogger(__name__)


def log(*args, **kwargs):
    print(args, kwargs)


def create():
    return DeviceProxy("ID16NA/foil/bpm4")

def subscribe(d):
    print("subscribe change event")
    try:
        d.subscribe_event(
            "positionId",
            PyTango.EventType.CHANGE_EVENT,
            log,
            [],
            False)
    except:
        print("arg")
    print("subscribe attr_conf event")
    try:
        d.subscribe_event(
            "positionId",
            PyTango.EventType.ATTR_CONF_EVENT,
            log,
            [],
            False)
    except:
        print("arg")
    print("subscribe end")


def test1():
    class T(threading.Thread):
        def run(self):
            d = create()
            subscribe(d)
    t = T()
    t.start()
    t.join()

def test2():
    g = gevent.spawn(create)
    d = g.get()
    g = gevent.spawn(subscribe, d)
    g.join()


def test3():
    d = []
    class T(threading.Thread):
        def run(self):
            d.append(create())
    t = T()
    t.start()
    t.join()
    g = gevent.spawn(subscribe, d[0])
    g.join()

Mmm there is surely a difference between subscribing in a greenlet and a thread. But we need an expert in PyTango to give us some feedback here. Maybe @tiagocoutinho can provide some feedback.

Is there any possibility of upgrading to Python 3?

No. No way to switch to Python 3. But we found a workaround on our side. In our case, the thread was a poller (infinite loop), and the sleep was not gevent really. Fixing that fixing the deadlock.

But in my test example, it would be nice to warn, as you do when using 2 different threads, but that's maybe not an obvious test. Then feel tree to close the issue.

Good news. We will add a warning to the documentation.

I don't think any body read the docs

I cannot help giving some good advice here : RTFM 8-)