Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help understanding ruby's Process.detach

Tags:

ruby

I'm learning systems programming through ruby and I'm having trouble understanding this behavior:

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)

This outputs as I expect:

hello!
hello!
hello!
hello!
Terminating

However if I comment out Process.detach, the child process seems to only respond to the signal once (and after termination?):

Terminating
hello!

I'm confused as to why this happens when I don't detach the process, even though I sent it USR1 four times. Can someone help explain this behavior? I think I'm not understanding what it means to detach a process.

Thanks so much!

like image 785
ambertch Avatar asked Apr 18 '12 00:04

ambertch


1 Answers

It's all down to timing, I suspect - that is, the difference is due to how the instructions of your main process and the forked process are scheduled to run relative to each other.

When you do Process.detach, a new thread is created which waits on the exit result of the given process. You can replace the Process.detach with

Thread.new { Process.wait(pid) }

and get the same effect. I suspect that calling detach (and spawning a new thread) gives your forked process, as a side effect, a chance to be scheduled.

If you have no detach, then I would guess your forked process doesn't get a chance to run by the time you tell it to die.

You can see what I mean by relative timing by inserting some sleep calls in your code to see if you can get the same observed behavior without the detach.

For example, this seems to work for me, though your mileage may vary depending on your host platform:

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)

This produces:

hello!
hello!
hello!
hello!
Terminating
like image 73
Rich Drummond Avatar answered Oct 18 '22 20:10

Rich Drummond