DBus-Cherrypy проблема слияния

Я использую 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, но Я не нашел способ запуска CherryPy таким образом, чтобы он запускался и возвращался, так что я могу инициировать вещи DBus и иметь возможность вытащить это за дверь.

Мой последний вопрос: есть ли способ заставить вишневый старт не блокировать, а продолжать работать? Я хочу избавиться от потоков в этом примере и инициализировать cherrypy и dbus в основном потоке.

2 ответа

Решение

Я понял это. Очевидно, в 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())

Черт возьми, какой кошмар. Теперь, чтобы сделать это лучше.

Да; не используйте 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() для некоторых из них.

Другие вопросы по тегам