В многопоточной программе Python один поток иногда запрашивает ввод в консоль с использованием встроенного raw_input(). Я хотел бы иметь возможность закрыть программу во время вызова raw_input, набрав^C в оболочке (т. Е. С сигналом SIGINT). Однако, когда дочерний поток выполняет raw_input, набрав^C ничего не делает - KeyboardInterrupt не поднимается до тех пор, пока я не вернусь назад (оставив raw_input).Прерывание Python raw_input() в дочернем потоке с помощью^C/KeyboardInterrupt
Например, в следующей программе:
import threading
class T(threading.Thread):
def run(self):
x = raw_input()
print x
if __name__ == '__main__':
t = T()
t.start()
t.join()
Typing^C ничего не делает, только после ввода закончен. Однако, если мы просто позвоним T().run()
(т. Е. Однопоточный случай: просто запустите raw_input в основном потоке),^C немедленно закрывает программу.
Предположительно, это связано с тем, что SIGINT отправляется в основной поток, который подвешен (ожидание GIL), пока блокировки разветвленных потоков на консоли прочитаны. Основной поток не получает выполнение обработчика сигнала, пока он не захватит GIL после возврата raw_input. (Пожалуйста, исправьте меня, если я ошибаюсь в этом вопросе - я не эксперт по реализации потоковой реализации Python.)
Есть ли способ читать из stdin в виде raw_input, позволяя обрабатывать SIGINT по основному потоку и тем самым разрушить весь процесс?
[Я наблюдал поведение выше на Mac OS X и несколько различных дистрибутивов Linux.]
Edit: я неправильно охарактеризовал основную проблему выше. При дальнейшем расследовании это вызов основной нити к join()
, что предотвращает обработку сигналов: сам Гвидо ван Россу объяснил это the underlying lock acquire in join is uninterruptible. Это означает, что сигнал на самом деле откладывается до тех пор, пока весь поток не закончится - так что это вообще не имеет никакого отношения к raw_input
(только тот факт, что фоновый поток блокируется, так что соединение не завершается).
Не просто комбинировать потоки и перерывы ... [boromir.jpg] – JBernardo