JesseStorimerの優れた本「WorkingwithUnixProcesses」を読んでいます。終了した子プロセスからのシグナルのトラップに関するセクションで、彼はコードサンプルを提供します。
そのコードを少し変更して(以下を参照)、何が起こっているのかをもう少しわかりやすくしました。
- 親がシグナル間で自身の実行を再開すること(私はそれで見ることができます
puts
)、 wait
1つのステートメントで複数の子に対して実行されることtrap
(「CHLD信号を受信しました」の後に複数の「子pidが終了しました」が続く場合があります)。
期待される出力
通常、以下のコードからの出力は次のようになります。
parent is working hard
Received a CHLD signal
child pid 73408 exited
parent is working hard
parent is working hard
parent is working hard
Received a CHLD signal
child pid 73410 exited
child pid 73409 exited
All children exited - parent exiting too.
時折のエラー
しかし、たまに次のようなエラーが発生します。
trapping_signals.rb:17:in `write': deadlock; recursive locking (ThreadError)
from trapping_signals.rb:17:in `puts'
from trapping_signals.rb:17:in `puts'
from trapping_signals.rb:17:in `block in <main>'
from trapping_signals.rb:17:in `call'
from trapping_signals.rb:17:in `write'
from trapping_signals.rb:17:in `puts'
from trapping_signals.rb:17:in `puts'
from trapping_signals.rb:17:in `block in <main>'
from trapping_signals.rb:40:in `call'
from trapping_signals.rb:40:in `sleep'
from trapping_signals.rb:40:in `block in <main>'
from trapping_signals.rb:38:in `loop'
from trapping_signals.rb:38:in `<main>
ここで何が問題になっているのか誰かに説明してもらえますか?
コード
child_processes = 3
dead_processes = 0
# We fork 3 child processes.
child_processes.times do
fork do
# Each sleeps between 0 and 5 seconds
sleep rand(5)
end
end
# Our parent process will be busy doing some work.
# But still wants to know when one of its children exits.
# By trapping the :CHLD signal our process will be notified by the kernel
# when one of its children exits.
trap(:CHLD) do
puts "Received a CHLD signal"
# Since Process.wait queues up any data that it has for us we can ask for it
# here, since we know that one of our child processes has exited.
# We loop over a non-blocking Process.wait to ensure that any dead child
# processes are accounted for.
# Here we wait without blocking.
while pid = Process.wait(-1, Process::WNOHANG)
puts "child pid #{pid} exited"
dead_processes += 1
# We exit ourselves once all the child processes are accounted for.
if dead_processes == child_processes
puts "All children exited - parent exiting too."
exit
end
end
end
# Work it.
loop do
puts "parent is working hard"
sleep 1
end