0

我正在使用 python-dbus 和 cherrypy 来监控 USB 设备并提供 REST 服务来维护插入的 USB 设备的状态。我已经独立编写和调试了这些服务,并且它们按预期工作。

现在,我将这些服务合并到一个应用程序中。我的问题是:我似乎无法同时启动两个服务(cherrypy 和 dbus)。一个或另一个阻塞或超出范围,或未初始化。

我尝试将每个封装在自己的线程中,然后对它们调用 start 。这有一些奇怪的问题。

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开始而不是阻塞但继续工作?我想摆脱这个例子中的线程并在主线程中初始化cherrypy和dbus。

4

2 回答 2

3

是的; 不要使用cherrypy.quickstart。相反,解压它:

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

Quickstart 执行上述操作,但通过调用 engine.block() 完成。如果你的程序有 CherryPy 以外的一些主循环,省略对 engine.block 的调用,你应该没问题。但是,当您的外部主循环终止时,您仍然需要调用cherrypy.engine.stop():

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

还有一些其他的问题,比如 CherryPy 是否应该处理 Ctrl-C 和其他信号,以及它是否应该自动重新加载。这些行为取决于您,并且都相当容易启用/禁用。查看其中一些的cherrypy.quickstart() 源代码。

于 2009-12-30T01:45:13.407 回答
3

我想通了。显然,glib 中有一堆线程争用问题。如果您制作的应用程序中包含 DBusGMainLoop,则您无法在应用程序中创建另一个线程。新线程在调用 start() 时立即阻塞。再多的按摩也不会让新线程运行。

我发现一个站点对 dbus.mainloop.glib.threads_init() 有一个模糊的引用,以及在初始化新线程之前必须如何调用它。然而,当尝试这样做时,发现了一个新问题。抛出一个异常,说 g_thread_init() 必须在 dbus.mainloop.glib.threads_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())

天哪,真是一场噩梦。现在让它变得更好。

于 2009-12-31T00:03:59.963 回答