Обработчики сигналов Perl сбрасываются в блоки END
Это работает, как и ожидалось, так как Perl 5.10.1: SIGINT захвачены.
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
Но здесь SIGINT не попали в ловушку.
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
END {
sleep(20);
}
Это можно исправить, снова установив обработчик в END
блок, вот так:
END {
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
}
Но это не сработает, если у вас более одного блока: обработчики должны быть установлены заново для каждого блока.
Я пытался выяснить это, и я не могу найти объяснение в perldoc. Единственное упоминание об этом поведении, которое я могу найти, - это сноска из Практического программирования на Perl A D Marshall 1999-2005
Примечание. Сигналы, отправляемые в ваш скрипт, могут обходить блоки END.
Кто-нибудь объяснит это?
2 ответа
Это работает для меня: переустановите обработчик в блок END, который запускается первым (последний в коде).
use warnings;
use strict;
use feature 'say';
$SIG{INT} = sub { say "SIGINT: got zap!" };
#sleep 10;
say "done";
END { say "END, runs last" }
END { say "END, runs next to last. Sleep then print"; sleep 10; say "Woke up."; }
# Executed first in END phase. The sole purpose: to reinstall the handler
END {
$SIG{INT} = sub { say "SIGINT in END block, got zap" };
}
После запуска и Ctrl-C-ed через несколько секунд это печатает
сделанный. КОНЕЦ, работает рядом с последним. Спи потом печатай ^CSIGINT в блоке END, получил zap Проснулся. КОНЕЦ, работает последним
Так что вам нужно добавить END
блок, последний в коде, END { $SIG{INT} = 'IGNORE' }
,
Похоже, что изменение на "END" ${^GLOBAL_PHASE}
удаляет или иным образом отключает обработчик.
Но после того, как обработчик переустановлен в END
Этап эффективен во всем. Это чистейшее, конечно, делать в END
блок, который выполняется первым.
Я буду обновлять, когда (если) я понимаю более подробно и найти документацию по этому поведению.
Perldoc PerlMod говорит:
Кодовый блок "END" выполняется как можно позже, то есть после
perl
завершил выполнение программы и непосредственно перед выходом из интерпретатора, даже если он завершается в результатеdie()
функция. (Но не если это превращается в другую программу через "exec
"или когда вас унесет из воды по сигналу - вы должны поймать его в ловушку (если можете).)
Я ожидаю, что обработчики сигналов будут удалены непосредственно перед выходом из интерпретатора. Поэтому я не совсем понимаю, что удивительно или неожиданно.