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() для некоторых из них.