Как я могу поймать SIGINT в поточной программе Python? - PullRequest
12 голосов
/ 04 октября 2010

При использовании потокового модуля и класса Thread () SIGINT (Ctrl + C в консоли) не может быть перехвачен.

Почему и что я могу сделать?

Простая программа тестирования:

#!/usr/bin/env python

import threading

def test(suffix):
    while True:
        print "test", suffix

def main():
    for i in (1, 2, 3, 4, 5):
        threading.Thread(target=test, args=(i, )).start()

if __name__ == "__main__":
    main()

Попробуйте нажать Ctrl-C - ничего не происходит.

Ответы [ 2 ]

9 голосов
/ 04 октября 2010

Потоки и сигналы не смешиваются.В Python это даже больше, чем снаружи: сигналы доставляются только в один поток (основной поток);другие темы не получат сообщение.Вы ничего не можете сделать, чтобы прерывать потоки, кроме основного потока.Они находятся вне вашего контроля.

Единственное, что вы можете здесь сделать, это ввести канал связи между основным потоком и любыми запускаемыми вами потоками, используя модуль queue.Затем вы можете отправить сообщение потоку и заставить его прекратить (или сделать все, что вы хотите), когда оно увидит сообщение.

В качестве альтернативы, и часто это очень хорошая альтернатива, это не использовать потоки.Однако то, что использовать вместо этого, во многом зависит от того, чего вы пытаетесь достичь.

0 голосов
/ 27 сентября 2014

По сути, вы можете проверить, выдал ли родитель сигнал, прочитав очередь во время работы.Если родитель получает SIGINT, он выдает сигнал через очередь (в данном случае что угодно), и дети завершают свою работу и выходят ...

def fun(arg1, thread_no, queue):
   while True:
    WpORK...
    if queue.empty() is False or errors == 0:
     print('thread ', thread_no, ' exiting...')
     with open('output_%i' % thread_no, 'w') as f:
      for line in lines: f.write(line)
     exit()

threads = []
for i, item in enumerate(items):
 threads.append( dict() )
 q = queue.Queue()
 threads[i]['queue'] = q
 threads[i]['thread'] = threading.Thread(target=fun, args=(arg1, i, q))
 threads[i]['thread'].start()
try:
 time.sleep(10000)
except:
 for thread in threads:
  thread['queue'].put('TERMINATING')
...