2016-11-19 4 views
3

Это работает так, как ожидалось, поскольку Perl 5.10.1: SIGINT находятся в ловушке.Обработчики сигналов Perl сбрасываются в END-блоках

#!/usr/bin/perl 

use strict; 
use warnings; 

$SIG{INT} = sub { die "Caught a sigint $!" }; 

sleep(20); 

Но здесь SIGINTs являются не в ловушке.

#!/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. Единственное упоминание об этом поведении я могу найти, это сноска от Practical Perl Programming A D Marshall 1999-2005

Примечание Сигналы, которые отправляются на ваш скрипт, могут обходить блоки END.

Кто-нибудь объяснит это?

+0

работает нормально на 5.24 (кажется). У вас нет времени на тестирование, но что произойдет, если вы поместите обработчик sig в ​​блок BEGIN на 5.10 ... это что-то изменит? Я надеюсь и не думаю ... – stevieb

+0

Я проверил его снова с 5.22 дома, и у меня такое же поведение. Запустите затем Ctrl-C -> Caught ..., с конечным блоком: . Что касается блока BEGIN, на 5.22, установка обработчика там получает сигналы, пойманные, но с блоком END тоже сигналы все еще не пойманы. – gxtaillon

+0

Ты абсолютно прав. Я ошибался. Обработчик sig не поймает должным образом, даже в 5.24, как я сказал ранее. Я думал, что раньше делал это в коде, но почему-то я начинаю сомневаться в этом, так как не могу заставить его работать над несколькими perlbrew экземплярами. – stevieb

ответ

3

Это работает для меня: переустановите обработчик в блоке 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-эд через несколько секунд печатается

 
done. 
END, runs next to last. Sleep then print 
^CSIGINT in END block, got zap 
Woke up. 
END, runs last 

Так что вам нужно добавить END блок, последний в коде, END { $SIG{INT} = 'IGNORE' }.

Похоже, что изменение на «END» ${^GLOBAL_PHASE} удаляет или иным образом отключает обработчик.

Но как только обработчик переустановлен на этапе END, он эффективен повсюду. Разумеется, это чище всего сделать в блоке END, который выполняется первым.

Я буду обновлять, когда (если) Я понимаю больше деталей и нахожу документацию по этому поведению.

1

perldoc perlmod говорит:

код блока "END" выполняется как можно позже, то есть послеperl завершил выполнение программы и непосредственно перед переводчик вышел из, даже если он вышел из-за die() функция. (Но нет, если он превращается в другую программу через «exec» или выдувается из воды водой по сигналу - вы должны заманивать ее сами (если можете).)

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

 Смежные вопросы

  • Нет связанных вопросов^_^