обработка межпроцессного сигнала в Ruby

Я запускаю этот скрипт:

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 процесса.

Видеть

  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

person Vlad Krylov    schedule 03.08.2011    source источник


Ответы (1)


Вы всегда можете заставить ребенка игнорировать сигнал INT.

person tadman    schedule 03.08.2011
comment
Я хочу другое. Я исправил сценарий, чтобы быть более понятным - person Vlad Krylov; 03.08.2011
comment
Игнорируйте INT и отправьте дочернему процессу другой сигнал для завершения, например USR1 или HUP, в зависимости от того, что кажется подходящим. Добавьте еще один обработчик сигнала к дочернему элементу, чтобы перехватить его и правильно выйти. - person tadman; 03.08.2011