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