ゾンビが子供を待っているのはなぜですか?


11

私はさまざまな情報源を掘り下げていますが、子刈りの解剖学についての適切な説明が見つかりません。これは私が理解したいことの単純なケースです。

$ cat <( sleep 100 & wait ) &
[1] 14247
$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 S pts/17   00:00:00 bash
14249 12126 S pts/17   00:00:00 sleep 100
14251 14250 S pts/17   00:00:00 grep --color=auto 12126
$ kill -2 14248

$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 Z pts/17   00:00:00 [bash] <defunct>
14249 12126 S pts/17   00:00:00 sleep 100
14255 14254 S pts/17   00:00:00 grep --color=auto 12126

ゾンビが子供を待っているのはなぜですか?

これを説明できますか?これを広く理解するためにCを知ってBashソースコードを読む必要がありますか、それともドキュメントはありますか?私はすでに相談しました:

GNU bash、バージョン4.3.42(1)-release(x86_64-pc-linux-gnu)

Linux 4.4.0-31-generic#50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU / Linux


2
これは実際にはbashとは何の関係もないことに注意してください(bashをシェルとして使用することを選択した場合、多くのプロセスがbashによって開始されるという事実を除きます)。他のシェル(tcsh、ksh、zsh、&c)はすべてプロセスを開始し、それらを処理するために基本的に同じOS関数を実行します。
jamesqf

@jamesqf興味深い。コメントを本格的な回答に拡張したい場合は、それは素晴らしいことです。

1
それが実際の答えではないことを除いて、間違った場所で答えを探していることを指摘するだけです:-) * nixシステムプログラミングに関する優れた本は、私が書けるよりもはるかに優れた答えを提供するはずです。
jamesqf

回答:


17

ゾンビは子供を待っていません。他のゾンビプロセスと同様に、親が収集するまで残ります。

何が起こっているのかを理解するために、関連するすべてのプロセスを表示し、PPIDも確認する必要があります。次のコマンドラインを使用します。

ps -t $(tty) -O ppid,pgid

あなたが殺しているプロセスの親はですcat。何が起こるかというと、bashはcat <( sleep 100 & wait )サブシェルでバックグラウンドコマンドを実行します。このサブシェルが行うことは、リダイレクトを設定して外部コマンドを実行することだけなので、このサブシェルは外部コマンドに置き換えられます。以下がその概要です。

  • 元のbash(12126)は、子(14247)でforkバックグラウンドコマンドを実行するために呼び出しますcat <( sleep 100 & wait )
    • 子(14247)が呼び出しpipeてパイプを作成し、次に子を作成しforkてプロセス置換を実行しますsleep 100 & wait
      • 孫(14248)はバックグラウンドでfork実行するようsleep 100に要求します。孫はインタラクティブではないため、バックグラウンドプロセスは別のプロセスグループで実行されません。その後、孫はsleep退出を待ちます。
    • 子(14247)はsetpgid(インタラクティブシェルのバックグラウンドジョブなので、独自のプロセスグループを取得します)を呼び出して、execveを実行しますcat。(バックグラウンドプロセスグループでプロセスの置換が行われていないことに少し驚いています。)
  • あなたは孫(14248)を殺します。その親は実行さcatれており、子プロセスについて何も知らず、ビジネス呼び出しもありませんwait。孫の親はそれを刈り取らないので、孫はゾンビとして後に残ります。
  • 最終的に、cat終了します—強制終了するかsleep、パイプを返して閉じるためcat、入力の終わりが表示されます。その時点で、ゾンビの親は死ぬので、ゾンビはinitによって収集され、initはそれを取得します。

コマンドを次のように変更した場合

{ cat <( sleep 100 & wait ); echo done; } &

次にcat、元のbashプロセスの子ではなく、別のプロセスで実行しますecho done。最初の子は、実行するために遅れる必要があります。この場合、孫を殺しても、その子(その時点ではまだbashを実行している)がそれを刈り取るので、ゾンビとしてとどまることはありません。

参照してくださいLinuxのハンドルはプロセスをゾンビどのようにして孤児を持っているゾンビをすることはできますか?孤児はゾンビを刈り取ることによって邪魔されますか?


プロセスグループのことにもびっくりしました。バグのようで、bash masterブランチで修正されています。
PSkocik

「元のbashは子を待っています(14247)。」なぜ、またはどのように?子はバックグラウンドで実行されることになっており、明示的な呼び出しはありません。14247をcat待機していない元のbash(14246)と14248を待機していない(実行中の)14247の違いは何sleepですか?子供(14247)が失い、元のbash(14246)が失っていなかった誰が誰を待つかについての記憶はありますか、またはSIGCHLDのような呼び出し対象者と14247(現在実行中bash)のリストからのサブスクライブを解除しました14248に関して?

1
@tomas私は、元のbashがwaitその子を要求することを意味しました。これがどのように混乱するかがわかるので、時系列的には適切な時点でさえなかったその文を削除しました。プロセスが停止したという情報は、そのプロセスの親に送られます。プロセスは、他のプロセスの終了に関する情報を受け取るために「サブスクライブ」することはできません。
Gilles「SO-邪悪なことをやめなさい」

6

ゾンビは子供を待っていません。代わりに、ゾンビはすでに死んでいるプロセスであり(あなたの例のように、自分自身で、または殺されました)、コード、データ、スタックの割り当てが解除され、現在は終了コードのみが含まれており、親が呼び出すのwait(2)を待って取得します(したがって、最終的にプロセステーブルからプロセスエントリを完全に削除します)

あなたの例では、睡眠が終了する(または終了する)と、親は終了ステータスを読み取り、ゾンビを刈り取ります。詳細については、上記wait(2)を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.