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

2023-11-22

在多线程 Python 程序中,一个线程有时会使用内置函数请求控制台输入原始输入()。我希望能够在 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 上观察到了上述行为。]


Edit:我错误地描述了上面的根本问题。经过进一步调查,这是主线程的调用join()这阻碍了信号处理:Guido van Rossum 本人解释说join 中的底层锁获取是不可中断的。这意味着信号实际上被推迟到整个线程完成——所以这实际上与raw_input根本没有(只是后台线程阻塞,因此连接无法完成)。


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

while my_thread.isAlive():
    my_thread.join(5.0)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ^C/KeyboardInterrupt 中断子线程中的 Python raw_input() 的相关文章

随机推荐