Подтвердить что ты не робот

Как я могу поймать SIGINT в потоковой программе python?

При использовании модуля потоковой передачи и класса 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 - ничего не происходит.

4b9b3361

Ответ 1

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

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

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

Ответ 2

В принципе, вы можете проверить, выдал ли родитель сигнал, прочитав очередь во время работы. Если родитель получает 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')