Python SIGINT not catched

泪湿孤枕 提交于 2020-01-01 15:38:09

问题


I don't manage to understand why my SIGINT is never catched by the piece of code below.

#!/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()

To clean this code I would prefer try/except the join() and closing all threads in case of exception, would that work?


回答1:


One of the problems with multithreading in python is that join() more or less disables signals.

This is because the signal can only be delivered to the main thread, but the main thread is already busy with performing the join() and the join is not interruptible.

You can deduce this from the documentation of the signal module

Some care must be taken if both signals and threads are used in the same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform signal() operations in the main thread of execution. Any thread can perform an alarm(), getsignal(), pause(), setitimer() or getitimer(); only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Python signal module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can’t be used as a means of inter-thread communication. Use locks instead.

You can work your way around it, by busy-looping over the join operation:

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

This is, however, none to efficient:

The workaround of calling join() with a timeout has a drawback: Python's threading wait routine polls 20 times a second when given any timeout. All this polling can mean lots of CPU interrupts/wakeups on an otherwise idle laptop and drain the battery faster.

Some more details are provided here:

Python program with thread can't catch CTRL+C

Bug reports for this problem with a discussion of the underlying issue can be found here:

https://bugs.python.org/issue1167930

https://bugs.python.org/issue1171023



来源:https://stackoverflow.com/questions/29660830/python-sigint-not-catched

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!