Dbus/GLib 主循环,后台线程
我刚开始接触DBus和事件驱动编程。我要创建的服务实际上分为三个部分,但其中两个主要是“服务器”相关的东西。
1) 实际的DBus服务器通过HTTPS与远程网站通信,管理会话,并向客户端传递信息。
2) 服务的另一个部分每两分钟调用一个保持活跃的页面,以保持与外部网站的会话活跃。
3) 客户端会向服务发起请求,以获取服务中的信息。
我找到了一些简单的示例程序,正在尝试将它们调整为原型的第1和第2部分。我想把它们放在一个程序里运行,而不是为两个部分分别写程序。
我遇到的问题是,在我的保持活跃线程中调用time.sleep(X)时,线程会进入睡眠状态,但永远不会醒来。我觉得是因为GLib主循环没有释放全局解释器锁(GIL)。
这是我的线程代码:
class Keepalive(threading.Thread):
def __init__(self, interval=60):
super(Keepalive, self).__init__()
self.interval = interval
bus = dbus.SessionBus()
self.remote = bus.get_object("com.example.SampleService", "/SomeObject")
def run(self):
while True:
print('sleep %i' % self.interval)
time.sleep(self.interval)
print('sleep done')
reply_status = self.remote.keepalive()
if reply_status:
print('Keepalive: Success')
else:
print('Keepalive: Failure')
从打印的语句来看,我知道睡眠开始了,但我从来没有看到“睡眠完成”。
这是主代码:
if __name__ == '__main__':
try:
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
name = dbus.service.BusName("com.example.SampleService", session_bus)
object = SomeObject(session_bus, '/SomeObject')
mainloop = gobject.MainLoop()
ka = Keepalive(15)
ka.start()
print('Begin main loop')
mainloop.run()
except Exception as e:
print(e)
finally:
ka.join()
还有一些其他观察:
我看到“开始主循环”的消息,所以我知道它正在运行。然后,我看到“睡眠 %i”,之后就没有任何输出了。
如果我按下^C,那么我会看到“睡眠完成”。大约20秒后,我会收到来自self.run()的异常,提示远程应用没有响应:
DBusException: org.freedesktop.DBus.Error.NoReply: 没有收到回复。可能的原因包括:远程应用没有发送回复,消息总线安全策略阻止了回复,回复超时,或者网络连接中断。
在服务器中运行我的保持活跃代码的最佳方法是什么?
谢谢,
1 个回答
在使用 gobject
时,你需要明确地开启多线程功能,这可以通过调用 gobject.threads_init()
来实现。想了解更多背景信息,可以查看 PyGTK 常见问题解答。
另外,针对你描述的目的,使用超时(timeout)似乎更合适。可以这样使用:
# Enable timer
self.timer = gobject.timeout_add(time_in_ms, self.remote.keepalive)
# Disable timer
gobject.source_remove(self.timer)
这段代码会每隔 time_in_ms
(毫秒)调用一次 keepalive
函数。想要了解更多细节,可以参考 PyGTK 参考文档。