2009-12-29 146 views
0

我正在使用python-dbus和cherrypy監視USB設備並提供REST服務,以便在插入的USB設備上保持狀態。我已經獨立編寫並調試了這些服務,並且按預期工作。DBus-Cherrypy合併問題

現在,我正在將這些服務合併到一個應用程序中。我的問題是: 我似乎無法讓兩個服務(cherrypy和dbus)一起啓動。其中一個或另一個阻止或超出範圍,或未被初始化。

我試過在每個線程中封裝每個線程,然後調用它們的開始。這有一些奇怪的問題。

class RESTThread(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 

    def run(self): 
     cherrypy.config.update({ 'server.socket_host': HVR_Common.DBUS_SERVER_ADDR, 'server.socket_port': HVR_Common.DBUS_SERVER_PORT, }) 
     cherrypy.quickstart(USBRest()) 

class DBUSThread(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 

    def run(self): 
     DBusGMainLoop(set_as_default=True) 
     loop = gobject.MainLoop() 
     DeviceAddedListener() 
     print 'Starting DBus' 
     loop.run() 

print 'DBus Python Started' 
if __name__ == '__main__': 
    # Start up REST 

    print 'Starting REST' 
    rs = RESTThread() 
    rs.start() 

    db = DBUSThread() 
    db.start() 

    #cherrypy.config.update({ 'server.socket_host': HVR_Common.DBUS_SERVER_ADDR, 'server.socket_port': HVR_Common.DBUS_SERVER_PORT, }) 
    #cherrypy.quickstart(USBRest()) 

    while True: 
     x = 1 

當這個代碼運行時,CherryPy的代碼不會完全初始化。當插入USB設備時,cherrypy會繼續初始化(好像線程以某種方式鏈接),但不起作用(不會提供數據甚至在端口上建立連接)我已經查看了cherrypys wiki頁面,但還沒有找到一種啓動cherrypy的方式,以便它能夠進入並返回,所以我可以啓動DBus的東西,使其能夠將其解鎖。

我的最終問題是:有沒有辦法讓櫻桃開始,不阻止,但繼續工作?我想擺脫這個例子中的線程,並在主線程中初始化cherrypy和dbus。

+0

我試過這個: http://stackoverflow.com/questions/510821/how-to-write-a-functional-test-for-a-dbus-service-written-in-python/762079#762079 現在cherrypy工作得很好,但loop.run()似乎沒有工作。 – Therealstubot

回答

3

我想通了。顯然,在glib中有一堆線程爭用問題。如果您製作的應用程序中包含DBusGMainLoop,則無法在應用程序中創建另一個線程。新線程在調用start()時立即阻塞。沒有任何數量的按摩會讓新線程運行。

我發現一個對dbus.mainloop.glib.threads_init()有一個不清楚的引用的站點,以及在初始化一個新線程之前如何調用這個站點。然而,當嘗試這個時發現一個新問題。在調用dbus.mainloop.glib.threads_init()之前,必須調用g_thread_init()時引發異常。更多搜索發現了對gobject.threads_init()的另一個模糊引用。它似乎很合適,所以經過多次實驗,我發現了正確的順序。

下面是解決方案。

dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 
gobject.threads_init() 
dbus.mainloop.glib.threads_init()  
DBUSMAINLOOP = gobject.MainLoop() 

print 'Creating DBus Thread' 
DBUSLOOPTHREAD = threading.Thread(name='glib_mainloop', target=DBUSMAINLOOP.run) 
DBUSLOOPTHREAD.start() 

print 'Starting REST' 
cherrypy.config.update({ 'server.socket_host': Common.DBUS_SERVER_ADDR, 'server.socket_port': Common.DBUS_SERVER_PORT, }) 
cherrypy.quickstart(USBRest()) 

什麼是惡夢。現在,讓它變得更好。

3

是;不要使用cherrypy.quickstart。取而代之,解壓縮它:

cherrypy.config.update(conf) 
cherrypy.tree.mount(USBREST()) 
cherrypy.engine.start() 

快速入門做到了上述,但通過調用engine.block()完成。如果你的程序有一些CherryPy以外的主循環,可以省略對engine.block的調用,你應該沒問題。然而,當你的外國主循環終止,你仍然要調用cherrypy.engine.stop():

loop = gobject.MainLoop() 
try: 
    loop.run() 
finally: 
    cherrypy.engine.stop() 

還有一些其他陷阱,像CherryPy的是否應該處理按Ctrl-C等信號,並是否應該自動重新加載。這些行爲取決於你,並且很容易啓用/禁用。查看其中一些的cherrypy.quickstart()源代碼。

+0

我試過了,有幾種方法沒有成功。我設法弄清楚了這個問題。顯然,啓動glib循環(對於DBus messenger)不會讓任何其他線程在應用程序中啓動,直到執行一系列thread_init()調用。我將在原文中詳細說明這一點。 如果新的glib循環不存在,您的解決方案將可用。 – Therealstubot