使用^ C / KeyboardInterrupt在子线程中中断Python raw_input()

时间:2012-02-13 22:59:40

标签: python input python-multithreading sigint control-c

在多线程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的方式从stdin读取,同时允许主线程处理SIGINT,从而降低整个过程?

[我在Mac OS X和一些不同的Linux上观察到了上述行为。]


编辑:我错误地描述了上面的根本问题。在进一步调查中,主要线程呼吁join()阻止信号处理:Guido van Rossum自己解释了the underlying lock acquire in join is uninterruptible。这意味着信号实际上被推迟到整个线程完成 - 所以这实际上与raw_input完全无关(只是后台线程阻塞以便连接没有完成)。

2 个答案:

答案 0 :(得分:6)

当调用join时没有超时,它是不可中断的,但是当它被超时调用时,它是可中断的。尝试添加任意超时并将其置于while循环中:

while my_thread.isAlive():
    my_thread.join(5.0)

答案 1 :(得分:1)

这个期间真的没有简单的方法。

一种方法是重新组织和分解代码,使得在主线程上执行需要 Ctrl-C 可中断性的部分函数。您可以使用队列发送执行请求,同样也可以使用结果值。主线程需要一个输入队列,每个非主线程需要一个输出队列;和一个协调的主线程退出。显然,在任何给定时间只有一个阻塞函数以这种方式执行,这可能不是你想要的。

对于协调主线程退出,

Here's a working example of this idea略微反复使用信号量。