9

Ruby でシステム プログラミングを学んでいますが、この動作を理解するのに苦労しています。

pid = fork do
  Signal.trap("USR1") do  
    puts "hello!"
  end
  Signal.trap("TERM") do
    puts "Terminating"
    exit
  end
  loop do
  end
end

Process.detach(pid)

Process.kill("USR1", pid)
Process.kill("USR1", pid)
Process.kill("USR1", pid)
Process.kill("USR1", pid)

Process.kill("TERM", pid)

これは私が期待するように出力されます:

hello!
hello!
hello!
hello!
Terminating

ただし、Process.detach をコメントアウトすると、子プロセスはシグナルに 1 回だけ応答するように見えます (終了後?):

Terminating
hello!

USR1 を 4 回送信したにもかかわらず、プロセスをデタッチしないとなぜこれが起こるのか、私は混乱しています。誰かがこの動作を説明できますか? プロセスを分離することの意味を理解していないと思います。

本当にありがとう!

4

1 に答える 1

8

それはすべてタイミングにかかっていると思います-つまり、違いは、メインプロセスとフォークされたプロセスの命令が互いに相対的に実行されるようにスケジュールされているためです。

Process.detach を実行すると、指定されたプロセスの終了結果を待機する新しいスレッドが作成されます。Process.detach を次のように置き換えることができます

Thread.new { Process.wait(pid) }

同じ効果が得られます。detach を呼び出す (そして新しいスレッドを生成する) と、フォークされたプロセスが副作用としてスケジュールされる可能性があると思われます。

デタッチがない場合、分岐したプロセスは、終了するように指示するまでに実行する機会がないと思います。

コードにいくつかのスリープ呼び出しを挿入することで、相対的なタイミングが何を意味するかを確認できます。これにより、デタッチなしで観察された同じ動作が得られるかどうかを確認できます。

たとえば、これは私にとってはうまくいくようですが、マイレージはホストプラットフォームによって異なる場合があります。

pid = fork do
  Signal.trap("USR1") do
    puts "hello!"
  end
  Signal.trap("TERM") do
    puts "Terminating"
    exit
  end
  loop do
  end
end

sleep(1)

Process.kill("USR1", pid)
Process.kill("USR1", pid)
Process.kill("USR1", pid)
Process.kill("USR1", pid)

sleep(1)

Process.kill("TERM", pid)

これにより、次が生成されます。

hello!
hello!
hello!
hello!
Terminating
于 2012-04-18T01:36:47.520 に答える