В чем разница между различными значениями $ SIG {CHLD}? - PullRequest
7 голосов
/ 05 декабря 2011

В чем разница между этими настройками?

$SIG{CHLD} = 'IGNORE'  
$SIG{CHLD} = 'DEFAULT'  
$SIG{CHLD} = ''  
$SIG{CHLD} = undef

В соответствии с разделом «Расширенное программирование в среде UNIX, 2-е издание» на рис. 10.1 значением SIGCHLD по умолчанию является «игнорировать».

Если «игнорировать» означает «SIG_IGN», то ни один ребенок никогда не будет зомби, и это не так.

Оттуда не становится намного яснее:

Если процесс специально устанавливает свое расположение на SIG_IGN, потомки вызывающего процесса не будет генерировать процессы зомби. Обратите внимание, что это отличается от его действия по умолчанию (SIG_DFL), которое из рисунка 10.1 следует игнорировать. Вместо этого, по завершении, статус этих дочерних процессов отбрасывается.

Мне трудно ухватиться за влияние различных значений (или неопределенных не значений). До сих пор решение состояло в том, чтобы поворачивать эти варианты, пока я не получу желаемое поведение, и я бы лучше понял, как именно каждое значение определяет поведение сигнала.

Поведение: дочерний процесс вызывает «систему» ​​или использует обратные пометки, которые создают другого дочернего процесса, и сигнал обычно будет перехвачен неправильным (родительским) обработчиком. Настройка локального обработчика может работать, но я не понимаю, какое значение является наиболее подходящим, если я хочу, чтобы сигнал от внучки ничего не делал.

Может кто-нибудь, пожалуйста, осветить меня?

UPDATE: Основываясь на отзывах икегами, я провел определенное тестирование. Поведение, по крайней мере частично, зависит от платформы.

Рассмотрим следующий фрагмент:

$SIG{CHLD} = sub {
    while( ( my $child = waitpid( -1, &WNOHANG ) ) > 0 ) {
        print "SIGNAL CHLD $child\n";
    }
};

my $pid = fork();

if( ! $pid ) {
    system( 'echo Grandchild PID = $$' );
    sleep 2;
    exit;
}

print "Child PID = $pid\n";
sleep 5;

Perl 5.8.6 в Solaris 10 будет отображать сообщения "SIGNAL CHLD" для PID вызова system (). Делать что-нибудь, даже тривиально, как

local $ SIG {CHLD};

у ребенка будут подавлять эти сообщения.

На каждом другом аромате, который я пробовал, жнец никогда не видит ребенка.

Ответы [ 4 ]

12 голосов
/ 05 декабря 2011

Существует два способа избежать создания процессов-зомби:

  1. явно установить $SIG{CHLD}='IGNORE'
  2. явно пожинать мертвых детей с помощью вызовов 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, если таковой имеется, всегда доставляется впроцесс, который породил дочерний процесс, поэтому я не считаю правильным сказать, что SIGCHLD из процесса внука (из вызова system в дочернем процессе) перехватывается в родительском процессе.Вероятно, происходит то, что ваш дочерний процесс наследует обработчик сигнала от своего родительского процесса.

system и обратные пометки (в большинстве систем) сгенерируют SIGCHLD при завершении и установят $?значение со статусом выхода команды.Но Perl сам пожнет эти подпроцессы, и вы не сможете перехватить идентификатор процесса при вызове system или обратных вызовов с помощью wait или waitpid.

10 голосов
/ 05 декабря 2011

См. %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

$
2 голосов
/ 19 июня 2015

Существует два разных значения слова "игнорировать", и они встречаются в двух разных точках оценки.

Первое использование касается того, следует ли вообще доставлять сигнал. Когдадочерние процессы завершаются, обычно они удерживаются операционной системой, а сигнал CHLD отправляется его родителю.При установке $ SIG {CHLD} в значение 'IGNORE' система сообщает системе не генерировать сигнал на всех и просто разрешить выход дочернему процессу.Родитель не имеет возможности получить информацию о дочернем процессе, и зомби не получится.

Но если $ SIG {CHLD} отличается от 'IGNORE', это означает передачу сигнала родительскому процессу,в этот момент существует либо собственный обработчик сигнала, либо обработчик сигнала по умолчанию, и обработчик по умолчанию будет отличаться в разных системах или даже в версиях одной и той же операционной системы.Страница man book и signal (7) рассказывает о том, что происходит по умолчанию , если сигнал доставляется родительскому процессу (т. Е. Для обработчика не задано значение IGNORE).Таким образом, второе использование игнорирования связано с тем, какое действие принять для доставленного сигнала .Например, SIGINT приведет к завершению вашего процесса, а SIGSTOP заставит ваш процесс «остановиться», хотя пользовательские обработчики сигналов изменяют эти действия по умолчанию.

Для сигнала SIGCHLD по умолчанию «игнорировать» его, но при использовании это просто означает, что (родительский) процесс просто продолжает нормально выполняться, пока дочерний процесс ожидает (т. Е. Нетпрекращение или прерывание родительского процесса).Затем вы можете подождать () этого позже, чтобы получить информацию и избежать зомби.

1 голос
/ 05 апреля 2016

$ SIG {CHLD} = 'IGNORE'

Это передается в ОС как SIG_IGN, который в соответствии с документацией по ОС заставляет дочерние процессы завершаться, превращаясь в зомби (илисообщая родительский код своего выхода).

$ SIG {CHLD} = 'DEFAULT'
$ SIG {CHLD} = ''
$ SIG {CHLD} = undef

Все они одинаковы на уровне ОС (они будут вызывать signal () с SIG_DFL).Однако некоторые пакеты perl, особенно AnyEvent :: child, не будут работать, если для $ SIG {CHLD} установлено значение «DEFAULT».

...