【问题标题】:python gobject.mainloop gobbles signal eventspython gobject.mainloop 吞噬信号事件
【发布时间】:2018-05-18 17:38:48
【问题描述】:

我有一个模块使用python“线程”进行并发,使用“信号”进行关闭挂钩:

signal.signal(signal.SIGINT, self.shutdownhook)

我有另一个使用 dbus 和 gobject 的模块

dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
....
GObject.threads_init()
mainloop = GObject.MainLoop()
mainloop.run()

当我单独运行它们时,它们都按预期运行,ctrl+c 通过“KeyboardInterrupt”导致终止。

但是,当我一起运行它们时,主循环会终止,但永远不会调用关闭挂钩 - 没有kill -9 pid,进程不会终止。

谁能解释一下为什么会发生这种情况,以及如何最好地整合这两个模型

这是一个突出我的问题的工作示例。我无法仅使用 CTRL+C 退出程序,并且在这种情况下也不会调用关闭挂钩。

import threading
import signal
import sys
from gi.repository import GObject


def runMainloop():
        print('running mainloop')
        mainloop.run()

def shutdown():
        print('shutdown')

def readInput():
        print('readInput')
        print(sys.stdin.readline())

if __name__ == '__main__':
        signal.signal(signal.SIGINT, shutdown)
        signal.signal(signal.SIGTERM, shutdown)
        GObject.threads_init()
        mainloop = GObject.MainLoop()

        mainloopThread = threading.Thread(name='mainloop', target=runMainloop)
        mainloopThread.setDaemon(True)
        mainloopThread.start()
        print('started')

        inputThread = threading.Thread(name='input', target=readInput)
        inputThread.start()
        print('started input')

【问题讨论】:

    标签: python dbus gobject


    【解决方案1】:

    没有人感兴趣,让我试试。

    只是在同一页面上:

    import signal
    from gi.repository import GObject
    
    GObject.threads_init()
    mainloop = GObject.MainLoop()
    
    signal.signal(signal.SIGINT, lambda n, f: mainloop.quit())
    
    mainloop.run()
    

    此代码有效:

    import signal
    from gi.repository import GObject
    
    signal.signal(signal.SIGINT, lambda n, f: print("kill"))
    
    GObject.threads_init()
    mainloop = GObject.MainLoop()
    mainloop.run()
    

    我首先注册了信号处理程序,然后启动了循环。奇怪的是它没有被调用。然而结果是 - 正如预期的那样......

    附带说明 - 根据他们的文档... mainloop 已弃用。这是第一件事。

    编辑

    这里是从stdin 中读取MainLoop 的示例:

    import signal
    import sys
    from gi.repository import GObject, GLib
    
    GObject.threads_init()
    
    def readInput():
        print('readInput\n')
        while True:
            input = sys.stdin.readline()
            print(input)
            if input.strip() == 'exit':
                print('closing main loop')
                mainloop.quit()
                print('terminating thread')
                return
    
    if __name__ == '__main__':
        signal.signal(signal.SIGINT, signal.SIG_DFL)
    
        mainloop = GObject.MainLoop.new(None, False)
        GObject.timeout_add(1000, readInput)
    
        # inputThread = threading.Thread(name='input', target=readInput)
        # inputThread.start()
        # print('started input')
    
        print('running mainloop\n')
        try:
            mainloop.run()
        except KeyboardInterrupt:
            mainloop.quit()
    

    添加.new(None, False) 允许CTRL-C 正常工作。取自herehere 也是另一个关于将脉冲音频控制器与GLib/GObject 循环集成的线程。有关于将 dbus 与循环集成的示例,但我不确定您希望采用哪种方式...

    【讨论】:

    • 谢谢,但这似乎无济于事。我已经用一个更好的工作示例更新了这个问题。
    • 是的,问题是MainLoop 占用了所有资源,而且自从 GIL 以来 Python 采用单线程......与 DBus 集成的唯一方法是将您的“东西”放入 MainLoop 事件中系统。网上有例子,我会尝试更新答案来处理。
    • ok .. 我很困惑,因为我的其他线程似乎工作得很好,只是信号/关机从未被触发。所以 MainLoop 吞噬了信号?也许我可以在 MainLoop 中添加一个关闭挂钩?
    • 根据他们的文档MainLoop 接受该信号。我也不明白——信号可以由主线程控制……也许是因为在 Python 之外做的?我的意思是在 C/C++/SharedObject... 不确定。
    【解决方案2】:

    添加一个计时器使循环接收 Unix 信号。

    import gi
    from gi.repository import GLib
    import signal
    
    GLib.threads_init()
    
    mainloop = GLib.MainLoop()
    
    signal.signal(signal.SIGTERM, lambda signum, frame: mainloop.quit())
    
    GLib.timeout_add(1000, lambda *args: (print("tick") or True))
    
    try:
        mainloop.run()
    except KeyboardInterrupt:
        print()
    

    【讨论】:

      猜你喜欢
      • 2017-01-03
      • 1970-01-01
      • 2019-02-24
      • 1970-01-01
      • 1970-01-01
      • 2016-04-23
      • 2012-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多