В многопоточной программе 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
(просто тот факт, что фоновый поток блокируется, поэтому соединение не завершается).