8

これらの設定の違いは何ですか?

$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 $child\n";
    }
};

my $pid = fork();

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

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

Solaris 10 上の Perl 5.8.6 は、system() 呼び出しの PID に対して「SIGNAL CHLD」メッセージを表示します。些細なことでも何でもする

ローカル $SIG{CHLD};

子でそれらのメッセージを抑制します。

私が試した他のすべてのフレーバーでは、死神は子供を見ることはありません.

4

4 に答える 4

13

ゾンビ プロセスの作成を回避するには、次の 2 つの方法があります。

  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}が に設定されている場合、常に -1 を返し'IGNORE'、を設定しないでください。waitwaitpid$?

は、もしあれば、常に子プロセスを生成したプロセスに配信されるため、孫プロセスからの (子プロセスの呼び出しからの) が親プロセスでキャッチされているSIGCHLDと言うのは正しくないと思います。おそらく、子プロセスが親プロセスからシグナルハンドラを継承していることが原因です。SIGCHLDsystem

systemまた、バッククォートは (ほとんどのシステムで) 完了時に を生成し、コマンドの終了ステータスで値をSIGCHLD設定します。$?しかし、Perl はこれらのサブプロセス自体を取得するため、 or を使用した or バッククォート呼び出しのプロセス ID を取得することはできませsystemん。waitwaitpid

于 2011-12-05T18:09:54.693 に答える
11

を参照してください%SIG

$SIG{CHLD} = 'IGNORE';プロセスが SIGCHLD シグナルを無視するようにします。

$SIG{CHLD} = 'DEFAULT';あなたのプロセスは、あなたが混乱していなかったか、$SIG{CHLD}または同等のものとして、SIGCHLDシグナルを処理します。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

$
于 2011-12-05T18:17:38.953 に答える
2

「無視」には 2 つの異なる意味があり、2 つの異なる評価ポイントで発生しています。

最初の使用法は、信号を送信するかどうかに関するものです。子プロセスが終了すると、通常はオペレーティング システムによって保持され、CHLD シグナルがその親プロセスに送信されます。$SIG{CHLD} を 'IGNORE' に設定すると、シグナルまったく生成せず、子プロセスを終了させるようにシステムに指示します。親は子プロセスに関する情報を取得する機会がなく、ゾンビは発生しません。

しかし、$SIG{CHLD} が 'IGNORE' 以外の場合は、親プロセスにシグナルを配信することを意味し、その時点でカスタム シグナル ハンドラーまたはデフォルト シグナル ハンドラーのいずれかが存在し、デフォルト ハンドラーは状況によって異なります。システムまたは同じオペレーティング システムのバージョン。book と signal(7) のマニュアル ページでは、シグナルが親プロセスに配信された場合(つまり、ハンドラが 'IGNORE' に設定されていない場合) にデフォルトで何が起こるかについて説明しています。したがって、ignore の 2 番目の使用法は、配信されたシグナルに対して実行するアクションに関連しています。たとえば、SIGINT はプロセスを終了させ、SIGSTOP はプロセスを「一時停止」させますが、カスタム シグナル ハンドラはこれらのデフォルト アクションを変更します。

SIGCHLD シグナルの場合、デフォルトではそれを「無視」しますが、この使用法では、子プロセスが待機している間 (親プロセスの終了や中止がない)、(親) プロセスが正常に実行を継続することを意味します。その後、後で wait() して情報を取得し、ゾンビを回避できます。

于 2015-06-19T01:54:00.127 に答える
1

$SIG{CHLD} = '無視'

これは SIG_IGN として OS に渡され、OS のドキュメントによると、子プロセスはゾンビになる (または終了コードを親に報告する) ことなく終了します。

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

これらは OS レベルではすべて同じです (SIG_DFL で signal() を呼び出します)。ただし、一部の perl パッケージ、特に AnyEvent::child は、$SIG{CHLD} が 'DEFAULT' に設定されていると機能しません。

于 2016-04-04T22:11:58.863 に答える