在多线程 Python 程序中,一个线程有时会使用内置的raw_input()请求控制台输入。我希望能够在 raw_input 提示符下通过在 shell 中键入 ^C 来关闭程序(即,使用 SIGINT 信号)。但是,当子线程正在执行 raw_input 时,键入 ^C 什么都不做——直到我按下回车键(离开 raw_input)才引发 KeyboardInterrupt。
例如,在以下程序中:
import threading
class T(threading.Thread):
def run(self):
x = raw_input()
print x
if __name__ == '__main__':
t = T()
t.start()
t.join()
在输入完成之前,键入 ^C 不会执行任何操作。但是,如果我们只是调用T().run()
(即单线程情况:只在主线程中运行 raw_input),^C 会立即关闭程序。
据推测,这是因为 SIGINT 被发送到主线程,主线程被挂起(等待 GIL),而分叉线程在控制台读取时阻塞。在 raw_input 返回后,主线程在获取 GIL 之前不会执行其信号处理程序。(如果我对此有误,请纠正我——我不是 Python 线程实现方面的专家。)
有没有办法以类似 raw_input 的方式从标准输入读取,同时允许 SIGINT 由主线程处理,从而降低整个过程?
[我在 Mac OS X 和一些不同的 Linux 上观察到上述行为。]
编辑:我错误地描述了上面的潜在问题。在进一步的调查中,阻止信号处理的是主线程的调用join()
:Guido van Rossum 自己已经解释过 join 中的底层锁获取是 uninterruptible。这意味着信号实际上被推迟到整个线程完成 - 所以这实际上与所有无关raw_input
(只是后台线程阻塞以便连接没有完成的事实)。