В чем разница между различными значениями $SIG{CHLD}?
в чем разница между этими настройками?
$SIG{CHLD} = 'IGNORE'
$SIG{CHLD} = 'DEFAULT'
$SIG{CHLD} = ''
$SIG{CHLD} = undef
согласно "расширенному программированию в среде UNIX, 2-е издание", рис. 10.1 значение по умолчанию SIGCHLD - "игнорировать"."
Если "игнорировать" означает "SIG_IGN", то ни один ребенок никогда не будет зомби, и это не так.
оттуда не становится намного яснее:
Если процесс специально устанавливает свое расположение в SIG_IGN, дети вызова процесс не будет генерировать зомби-процессы. Заметить что это отличается от его действия по умолчанию (SIG_DFL), которое от рисунка 10.1 следует игнорировать. Вместо этого, по окончании, состояние этих дочерних процессов отбрасывается.
мне трудно понять, какое влияние оказывают различные значения (или неопределенное значение). До сих пор решение состояло в том, чтобы вращаться через эти выборы, пока я не получу желаемое поведение, и я бы предпочел точно понять, как каждый значение определяет поведение сигнала.
поведение: дочерний процесс вызывает "систему" или использует обратные палочки, которые создают другого ребенка, и сигнал обычно будет пойман неправильным (родительским) обработчиком. Настройка локального обработчика может работать, но я не понимаю, какое значение наиболее подходит, если я хочу, чтобы сигнал от внука ничего не делал.
может кто-нибудь просветить меня?
обновление: Основываясь на отзывах ikegami, Я провел специальное тестирование. Поведение, по крайней мере частично, зависит от платформы.
рассмотрим следующий фрагмент:
$SIG{CHLD} = sub {
while( ( my $child = waitpid( -1, &WNOHANG ) ) > 0 ) {
print "SIGNAL CHLD $childn";
}
};
my $pid = fork();
if( ! $pid ) {
system( 'echo Grandchild PID = $$' );
sleep 2;
exit;
}
print "Child PID = $pidn";
sleep 5;
Perl 5.8.6 на Solaris 10 отобразит сообщения "SIGNAL CHLD" для PID вызова system (). Делать что угодно, даже такое тривиальное, как
локальный $SIG{CHLD};
у ребенка будет подавлять эти сообщения.
на каждом другом вкусе, который я пробовал, жнец никогда не видит ребенка.
4 ответов
посмотреть %SIG
.
$SIG{CHLD} = 'IGNORE';
заставляет ваш процесс игнорировать сигналы SIGCHLD.
$SIG{CHLD} = 'DEFAULT';
заставляет ваш процесс обрабатывать сигналы SIGCHLD, как если бы вы не связывались с $SIG{CHLD}
или эквивалент. Согласно kill (1), процесс в моей системе по умолчанию игнорирует SIGCHLD
$SIG{CHLD} = '';
и $SIG{CHLD} = undef;
недопустимые значения.
Что касается жатвы, дети родителя, обработчик SIGCHLD которого явно установлен в IGNORE
будет пожинается автоматически системой, как только она выходит.
$ perl -e'
my $pid = fork;
if (!$pid) { sleep(1); exit; }
sleep(2);
system "ps -o pid,stat,command $pid";
'
PID STAT COMMAND
14667 ZN+ [perl] <defunct>
$ perl -e'
$SIG{CHLD}="IGNORE";
my $pid = fork;
if (!$pid) { sleep(1); exit; }
sleep(2);
system "ps -o pid,stat,command $pid";
'
PID STAT COMMAND
$
существует два способа избежать создания зомби-процессов:
- явно установлен
$SIG{CHLD}='IGNORE'
- пожинать мертвых детей эксплицитно с
wait
илиwaitpid
вызовы (это может быть сделано внутри обработчика SIGCHLD, но это не обязательно)
задание $SIG{CHLD}='IGNORE'
ловушки SIGCHLD на уровне операционной системы, очистка дочернего процесса без даже сигнализации вашей программы Perl.
другие настройки, в том числе 'DEFAULT'
, undef
, ""
, sub {}
, 'some_function_name_that_doesnt_even_exist'
вызовет сигнал, который будет доставлен в Perl,и ребенок не будет автоматически пожат.
пожиная сам процесс с wait
и waitpid
, вы можете получить дополнительную информацию, такую как статус выхода дочернего процесса и (более или менее) порядок завершения дочерних процессов. Если $SIG{CHLD}
установлено значение 'IGNORE'
, wait
и waitpid
всегда возвращайте -1 и не устанавливайте $?
.
на SIGCHLD
, если таковые имеются, всегда доставляется в процесс, который породил дочерний процесс, поэтому я не думаю, что вы правы, говоря, что a SIGCHLD
от процесса внука (от system
вызов в дочернем процессе) пойман в Родительском процессе. Вероятно, происходит то, что ваш дочерний процесс наследует обработчик сигнала от родительского процесса.
system
и backticks будет (в большинстве систем) генерировать SIGCHLD
по завершении и установит $?
значение со статусом выхода команды. Но Perl будет пожинать эти подпроцессы сам, и вы не сможете захватить идентификатор процесса system
или backticks вызов с wait
или waitpid
.
есть два разных значения для "игнорировать", и они происходят в двух различных точках оценки.
первое использование касается того, следует ли вообще подавать сигнал. когда дочерний процесс завершает работу, он обычно удерживается операционной системой и сигнал CHLD отправляется его родителю. При установке $SIG{CHLD} в "IGNORE" он говорит системе не генерировать сигнал на всех и просто позвольте дочернему процессу выйти. У родителя нет возможности чтобы получить информацию о процессе ребенка, и никаких зомби результата.
но если $SIG{CHLD} - это что-то иное, чем "игнорировать", это означает доставку сигнала родительскому процессу, в этот момент есть либо пользовательский обработчик сигнала, либо обработчик сигнала по умолчанию, и обработчик по умолчанию будет отличаться в разных системах или даже версиях одной и той же операционной системы. Книга и сигнал (7) man page говорят о том, что происходит по умолчанию если сигнал поставлен к родителю процесс (т. е. обработчик не установлен в "игнорировать"). Так что второе использование ignore связано с которым действие принять за доставленный сигнал. Например, SIGINT приведет к завершению процесса, а SIGSTOP - к "паузе", хотя пользовательские обработчики сигналов изменят эти действия по умолчанию.
для сигнала SIGCHLD значение по умолчанию - "игнорировать" его, но в этой использование это просто означает, что (родительский) процесс просто продолжается выполнение в обычном режиме, пока дочерний процесс ожидает (т. е. нет завершения или прерывания родительского процесса). Затем вы можете подождать () на нем позже, чтобы получить информацию и избежать зомби.
$SIG{CHLD} = 'IGNORE'
это передается в ОС как SIG_IGN, который, согласно документам ОС, заставляет дочерние процессы завершаться становлением зомби (или сообщением их кода выхода родительскому).
$SIG{CHLD} = 'DEFAULT'
$SIG{CHLD} ="
$SIG{CHLD} = undef
все они одинаковы на уровне ОС (они будут вызывать signal () с помощью SIG_DFL). Однако некоторые пакеты perl, в частности AnyEvent:: child, не будет работать, когда $SIG{CHLD} имеет значение 'DEFAULT'.