Обработчики сигналов 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"или когда вас унесет из воды по сигналу - вы должны поймать его в ловушку (если можете).)

Я ожидаю, что обработчики сигналов будут удалены непосредственно перед выходом из интерпретатора. Поэтому я не совсем понимаю, что удивительно или неожиданно.

Другие вопросы по тегам