Я запускаю этот скрипт:
t = fork do
Signal.trap "INT" do
puts "child"
exit
end
sleep 10
end
Signal.trap "INT" do
puts "parent"
Process.kill "INT", t
Process.waitpid t
exit
end
Process.waitpid t
Когда я нажимаю CTRL+C, я получаю
$ ruby sigtest.rb
^Cchild
parent
Вы можете видеть, что "INT" передается каждому процессу и Process.kill "INT", t
пытается убить процесс, который уже умер. Есть ли способ сделать так, чтобы пользовательский сигнал INT передавался только родителю? И вывод будет:
$ ruby sigtest.rb
^Cparent
child
Решение
Правила:
- Когда вы нажимаете ctrl+c, SIGINT передается всей группе процессов.
- Когда вы разветвляете новый процесс, обработчики сигналов не передаются новому процессу.
Поэтому, если вы хотите управлять сигналами дочернего процесса вручную, вам нужно изменить GID процесса.
Видеть
- http://corelib.rubyonrails.org/classes/Process/Sys.html#M001961
- http://ruby.runpaint.org/processes (параграф "Хеш параметров")
def system cmd
pid = fork do
exec cmd, {:pgroup => true}
end
Process.wait pid
$?.success?
end
def ` cmd # `make syntax highlight happy
readme, writeme = IO.pipe
pid = fork do
$stdout.reopen writeme
readme.close
exec cmd, {:pgroup => true}
end
writeme.close
data = readme.read
Process.wait pid
data
end