Невозможно убить Python script с помощью Ctrl-C

Я тестирую потоки Python со следующим script:

import threading

class FirstThread (threading.Thread):
        def run (self):
                while True:
                        print 'first'

class SecondThread (threading.Thread):
        def run (self):
                while True:
                        print 'second'

FirstThread().start()
SecondThread().start()

Это работает в Python 2.7 на Kubuntu 11.10. Ctrl + C не убьет его. Я также попытался добавить обработчик системных сигналов, но это не помогло:

import signal 
import sys
def signal_handler(signal, frame):
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

Чтобы убить процесс, я убиваю его с помощью PID после отправки программы на задний план с помощью Ctrl + Z, который не игнорируется. Почему Ctrl + C игнорируется так настойчиво? Как я могу это решить?

Ответ 1

Ctrl + C завершает основной поток, но поскольку ваши потоки не находятся в режиме демона, они продолжают работать, и это сохраняет работоспособность. Мы можем сделать их демонами:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

Но тогда возникает еще одна проблема - как только основной поток запустил ваши потоки, ему больше нечего делать. Таким образом, он выходит, и потоки мгновенно уничтожаются. Поэтому дайте сохранить живой поток:

import time
while True:
    time.sleep(1)

Теперь он будет печатать "первым" и "вторым", пока вы не нажмете Ctrl + C.

Изменить:, как отмечали комментаторы, потоки демона могут не получить возможность очищать такие вещи, как временные файлы. Если вам это нужно, то поймайте KeyboardInterrupt в основном потоке и скопируйте его очистку и завершение работы. Но во многих случаях, позволяя внезапным потокам демонов, возможно, достаточно хорошо.

Ответ 3

Я думаю, что лучше всего вызывать join() для ваших потоков, когда вы ожидаете, что они умрут. Я взял на себя смелость с вашим кодом, чтобы завершить циклы (вы также можете добавить туда все, что нужно для очистки). Переменная die проверяется на истинность при каждом проходе, а когда она True, то программа завершается.

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()