On 11/10/06, ara.t.howard / noaa.gov <ara.t.howard / noaa.gov> wrote:
>
> so i was hoping that some message would be sent to 't' in the child, 'kill'
> for instance, the shut it down.  however, this doesn't seem to be the case, it
> seems like the thread is killed without any message being sent to it, so that
> i cannot trigger an event on it's death.
>
> is this true?  any workarounds?
>

I did this quick experiment to see exactly what was going on. Create
the thread, fork a child, and then print out a message in the child
and in the parent.

$ cat tmp.rb

t = Thread.new{ sleep }

ObjectSpace.define_finalizer(t) {puts "t death in #{$$}"}
at_exit {puts "parent(#{$$}) death"}

fork {
  at_exit {puts "child(#{$$}) death"}
  puts "thread status '#{t.status}'"
  puts "sleeping in child"
  sleep 2
  exit
} and Process.wait

puts "sleeping in parent"
sleep 2

puts "DONE"

$ ruby tmp.rb
thread status 'false'
sleeping in child
child(29926) death
parent(29926) death
t death in 29926
sleeping in parent
DONE
parent(29925) death
t death in 29925

We see the parent death twice because the child ran the parent's
finalizers -- that is also why we see the thread death in the child.
However, the status of the thread on entering is "false". This means
that the thread has already terminated, but its finalizer does not get
called in the child until the child exits.

Ara, is your desire to close the socket at the beginning of the child
process or at the end?

Either way the workaround is the same. Define the finalizer as a Proc
object, and pass this Proc to the child. The child will call the Proc
either at the beginning of the fork or at the end using its own
at_exit call ...

$ cat tmp2.rb

t = Thread.new{ sleep }

finalizer = lambda {puts "t death in #{$$}"}
ObjectSpace.define_finalizer(t, finalizer)
at_exit {puts "parent(#{$$}) death"}

fork {
  at_exit {exit!}
  at_exit {puts "child(#{$$}) death"}
  at_exit {finalizer.call}
  puts "thread status '#{t.status}'"
  puts "sleeping in child"
  sleep 2
  exit
} and Process.wait


puts "sleeping in parent"
sleep 2

puts "DONE"

$ ruby tmp2.rb
thread status 'false'
sleeping in child
t death in 29967
child(29967) death
sleeping in parent
DONE
parent(29966) death
t death in 29966


Now, if you want to kill the socket at the start of the fork, then
just invoke the finalizer first.

$ cat tmp3.rb

t = Thread.new{ sleep }

finalizer = lambda {puts "t death in #{$$}"}
ObjectSpace.define_finalizer(t, finalizer)
at_exit {puts "parent(#{$$}) death"}

fork {
  at_exit {exit!}
  at_exit {puts "child(#{$$}) death"}
  finalizer.call
  puts "thread status '#{t.status}'"
  puts "sleeping in child"
  sleep 2
  exit
} and Process.wait


puts "sleeping in parent"
sleep 2

puts "DONE"

$ ruby tmp3.rb
t death in 29984
thread status 'false'
sleeping in child
child(29984) death
sleeping in parent
DONE
parent(29983) death
t death in 29983


Hope this makes sense.

TwP