В чем разница между Ctrl-C и SIGINT?
Я отлаживал программу Python, которая segfaults после получения исключения KeyboardInterrupt
. Обычно это делается нажатием Ctrl+C из оболочки. Чтобы проверить, исправил ли какой-то конкретный код ошибку, у меня была небольшая оболочка script, которая отправила SIGINT
в программу в произвольное время после запуска. Проблема заключается в том, что отправка Ctrl+C, по-видимому, оказывает иное влияние на программу, чем отправка сигнала SIGINT
и, следовательно, не вызывает появления ошибки, поэтому я довольно удивляюсь, какая разница между этими двумя действиями.
Программа вообще не выполняет никаких действий с клавиатурой и представляет собой просто программу python с некоторыми потоками/процессами в них. Он не устанавливает обработчики сигналов (хотя Python делает это), а stty -a
дает intr = ^C
. Я подозреваю, что может быть, что Ctrl+C отправляет SIGINT
всем подпроцессам/нити, а kill -INT
отправляет только основной процесс, но это как бы далеко не все мои подозрения.
Вот оболочка script, которая отправляет kill -INT
.
wait
while :; do
seconds="$(python -c 'import random; print random.random()*4')"
./mandos --debug --configdir=confdir \
--statedir=statedir --no-restore --no-dbus &
pid=$!
{ sleep $seconds; kill -INT $pid; } &
fg %./mandos
status=$?
if [ $status -gt 1 ]; then
echo "Failed exit $status after $seconds seconds"
break
fi
wait
done
Ответы
Ответ 1
^C
отправляет SIGINT
всем процессам в группе процесса переднего плана. Чтобы сделать эквивалент с помощью kill
, вы должны отправить сигнал в группу процессов (концепция уровня ОС):
kill -SIGINT -<pid>
или к заданию (концепция уровня оболочки, конвейер заканчивается на &
):
kill -SIGINT %
Ответ 2
Как описанный здесь:
Python по умолчанию устанавливает небольшое количество обработчиков сигналов: SIGPIPE игнорируется (поэтому ошибки записи на трубах и сокетах можно сообщать как обычные исключения на Python) и SIGINT преобразуется в Исключение KeyboardInterrupt. Все это можно переопределить.
Таким образом, поведение должно быть одинаковым между отправкой SIGINT и Ctrl + c.
Но вы должны быть осторожны с KeyboardInterrupt
, если где-то в вашем коде у вас есть
try:
...
except: # notice the lack of exception class
pass
это будет "есть" исключение KeyboardInterrupt.