Python SIGINT未被捕获。

3

我不明白为什么下面的代码无法捕获我的SIGINT信号。

#!/usr/bin/env python
from threading import Thread
from time import sleep
import signal

class MyThread(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.running = True

    def stop(self):
        self.running = False

    def run(self):
        while self.running:
            for i in range(500):
                col = i**i
                print col
                sleep(0.01)

global threads
threads = []

for w in range(150):
    threads.append(MyThread())

def stop(s, f):
    for t in threads:
        t.stop()

signal.signal(signal.SIGINT, stop)

for t in threads:
    t.start()

for t in threads:
    t.join()

为了清理这段代码,我更喜欢尝试/除外join()和在出现异常的情况下关闭所有线程,这样可以吗?

可能是Python中可中断的线程加入的重复问题。 - Trevor Boyd Smith
1个回答

8
在Python中使用多线程的一个问题是,join() 函数会或多或少地禁用信号。
这是因为信号只能传递到主线程,但主线程已经忙于执行 join(),而且 join 操作是不可中断的。
你可以从 signal 模块的文档中推断出这一点。

如果在同一个程序中同时使用信号和线程,则必须小心处理。在同时使用信号和线程时,要记住的基本事项是:始终在执行的主线程中执行 signal() 操作。任何线程都可以执行 alarm()、getsignal()、pause()、setitimer() 或 getitimer();只有主线程才能设置新的信号处理程序,而且主线程将是唯一接收信号的线程(即使底层线程实现支持向各个线程发送信号,Python 信号模块也会强制执行此操作)。这意味着信号不能用作线程间通信的手段。请改用锁。

你可以通过在 join 操作上进行忙循环来解决这个问题:
for t in threads:
    while t.isAlive():
        t.join(timeout=1)

然而,这并不是很有效:

使用带有超时参数的join()方法的解决方法存在一个缺陷:当Python线程等待时,如果给定任何超时时间,则会轮询20次每秒。所有这些轮询可能会导致在本来空闲的笔记本电脑上产生大量的CPU中断/唤醒,并更快地耗尽电池。

这里提供了更多细节:

Python程序中的线程无法捕获CTRL+C

关于这个问题的错误报告和底层问题讨论可以在这里找到:

https://bugs.python.org/issue1167930

https://bugs.python.org/issue1171023


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接