Juice Kang
Juice Kang

Reputation: 1

Python cannot work as dbus server and client in the multi-thread enviroment

I created the dbus server as the following code, named it as server1.py

#!/usr/bin/python2.7
import dbus.service
import dbus.glib
import glib
import gobject
from dbus.mainloop.glib import DBusGMainLoop


class APP_Server(dbus.service.Object):
    def __init__(self):
        bus = dbus.SessionBus(private = True, mainloop = DBusGMainLoop())
        bus_name = dbus.service.BusName('de.test.app1', bus)
        dbus.service.Object.__init__(self, bus_name, '/de/test/app1_obj_path')

    @dbus.service.method("test.app1.interface",)
    def is_ready(self):           
        return True

def publish_dbus():
    loop = glib.MainLoop()
    APP_Server()
    loop.run()

if __name__ == '__main__': 
    gobject.threads_init()
    dbus.glib.init_threads()
    publish_dbus()

And then I want to access dbus service in the server1.py by the following code, named it as server2.py which also will work as a dbus server.

#!/usr/bin/python2.7
import dbus.service
import dbus.glib
import glib
import dbus.mainloop
import gobject
from dbus.mainloop.glib import DBusGMainLoop
from threading import Thread
from time import sleep


class APP_Server(dbus.service.Object):
    def __init__(self):
        bus = dbus.SessionBus(private = True, mainloop = DBusGMainLoop())
        bus_name = dbus.service.BusName('de.test.app3', bus)
        dbus.service.Object.__init__(self, bus_name, '/de/test/app3_obj_path')

    @dbus.service.method("test.app3.interface",)
    def is_ready(self):           
        return True

def call_dbus():
    bus_name = 'de.test.app1'
    obj_path = '/de/test/app1_obj_path'
    interface_name = 'test.app1.interface'
    count = 1
    while count < 1000:
        proxy_bus = dbus.SessionBus(private = True)
        obj = None
        try:
            obj = proxy_bus.get_object(bus_name, obj_path)
        except:
            sleep(1)
            obj = proxy_bus.get_object(bus_name, obj_path)
        ready = obj.get_dbus_method('is_ready', interface_name)
        ready(pid_, bin_path)
        count += 1
        print count 

def publish_dbus():
    loop = glib.MainLoop()
    APP_Server()
    loop.run()

if __name__ == '__main__':
    gobject.threads_init()
    dbus.glib.init_threads()
    th1 = Thread(target = publish_dbus)
    th1.start()
    th2 = Thread(target = call_dbus)
    th2.start()
    sleep(10000000)

Then after run the server2.py, the application will terminated without finished all the dbus call in the thread "call_dbus".

And if I tried with the follwoing code, only changed the code in server2.py as the following:

FROM:

 proxy_bus = dbus.SessionBus(private = True)

TO:

  proxy_bus = dbus.SessionBus(private = True, mainloop = dbus.mainloop.NULL_MAIN_LOOP)

Now, there will have many connnections after the thread "callbus" finished by using the tools "d-feet" which can be used as a d-bus debugger to check if the dbus server is ready or if the dbus connection has been established.

If someone can make some suggeston to make it work normally??

Upvotes: 0

Views: 1335

Answers (1)

mata
mata

Reputation: 69042

What i've noticed is this:

  • Your bus/object names don't match.
  • You create a new dbus connection each time in your while loop. Very bad idea, specially seen that you don't close them.
    Either move the call out of the loop, or use a shared connection (private=False)
  • You don't really need an own thread to publish the dbus object, that's what the mainloop is for anyway.
  • If you run a mainloop in a different thread, make sure you have a way to stop, otherwise kill will be the only way of terminating your program. Or put int in your main thread, then it should at least react to Ctrl-C
  • The sleep at the end of your program is unnecessary. As long as there are running non-daemon threads around the program won't exit anyway.

Putting all this together, this should work:

#!/usr/bin/python2.7
import dbus.service
import dbus.glib
import glib
import dbus.mainloop
import gobject
from dbus.mainloop.glib import DBusGMainLoop
from threading import Thread
from time import sleep


class APP_Server(dbus.service.Object):
    def __init__(self):
        bus = dbus.SessionBus(private = True, mainloop = DBusGMainLoop())
        bus_name = dbus.service.BusName('de.test.app3', bus)
        dbus.service.Object.__init__(self, bus_name, '/de/test/app3_obj_path')

    @dbus.service.method("test.app3.interface",)
    def is_ready(self):           
        return True

def call_dbus():
    bus_name = 'de.test.app3'
    obj_path = '/de/test/app3_obj_path'
    interface_name = 'test.app3.interface'
    proxy_bus = dbus.SessionBus(private = True)
    count = 1
    while count < 1000:
        obj = None
        try:
            obj = proxy_bus.get_object(bus_name, obj_path)
        except:
            sleep(1)
            obj = proxy_bus.get_object(bus_name, obj_path)
        ready = obj.get_dbus_method('is_ready', interface_name)
        #ready(pid_, bin_path)
        count += 1
        print count 


if __name__ == '__main__':
    gobject.threads_init()
    dbus.glib.init_threads()
    loop = glib.MainLoop()
    server = APP_Server()
    #th1 = Thread(target = publish_dbus)
    #th1.start()
    th2 = Thread(target = call_dbus)
    th2.start()
    loop.run()

Upvotes: 2

Related Questions