Python SIGINT没有被捕获

时间:2015-04-15 21:01:20

标签: python multithreading sigint

我无法理解为什么我的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()并在异常的情况下关闭所有线程,这会有用吗?

1 个答案:

答案 0 :(得分:7)

python中多线程的一个问题是join()或多或少会禁用信号。

这是因为信号只能传递到主线程,但主线程已经忙于执行join()并且连接不可中断。

您可以从signal模块

的文档中推断出这一点
  

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

您可以通过忙于循环连接操作来解决它:

for t in threads:
    while t.isAlive():
        t.join(timeout=1)

然而,这没有效率:

  

使用超时调用join()的解决方法有一个缺点:   Python的线程等待例程每秒轮询20次   任何超时。所有这些轮询都意味着大量的CPU   在一台空闲的笔记本电脑上中断/唤醒并排空   电池更快。

此处提供了更多详细信息:

Python program with thread can't catch CTRL+C

可以在此处找到关于此问题的Bug报告以及对基础问题的讨论:

https://bugs.python.org/issue1167930

https://bugs.python.org/issue1171023