forking kills threads, if it didn't, this would hang:


   harp:~ > cat a.rb
   t = Thread.new{ sleep }
   fork{ t.join; exit } and Process.wait

   harp:~ > ruby a.rb


but, of course, it does not

now, say you need to know when a thread has been killed due to forking, it
appears there is no message sent to the thread:

   harp:~ > cat a.rb
   t = Thread.new{ sleep }
   class << t
     instance_methods.each{|m| undef_method m unless m[/__/]}
   end
   fork{ exit } and Process.wait


   harp:~ > ruby a.rb
   a.rb:4: warning: undefining `__send__' may cause serious problem
   a.rb:4: warning: undefining `__id__' may cause serious problem


otherwise we'd see an error thrown for some message being sent to 't'.


definining a finalizer is one way to trigger notification of thread death on
fork:


   harp:~ > cat a.rb
   t = Thread.new{ sleep }

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

   fork{ exit } and Process.wait


   harp:~ > ruby a.rb
   t death in 6671
   t death in 6670


but, for this to work you must inherit __every__ exit handler from the parent:

     harp:~ > cat a.rb
     t = Thread.new{ sleep }

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

     at_exit{ puts "parent(#{ $$ }) death" }

     fork{
       at_exit{ exit! }                       # don't inherit at_exit handlers from parent!!!
       at_exit{ puts "child(#{ $$ }) death" }
       exit
     } and Process.wait


     harp:~ > ruby a.rb
     child(6677) death
     parent(6676) death
     t death in 6676


as you see above, if we don't the finalizer is called only in the parent.


now, in my case i have a thread that's reading from a socket in the
background, when this thread dies and death trigger is fired.  this works
great.  this issue is that any fork in the code will duplicate the socket
being read from in the child, and i don't want that.  my thinking is that i
could handle this by trapping the finalization of the thread doing the reading
and, when it's finalized, shutdown the socket.  eg


   t = Thread.new{ socket.read; death_callback.call }

   ObjectSpace.define_finalizer(t){ socket.close }

   fork{
     # socket should get close here since t gets killed
     exit
   }

this issue is that i cannot inherit all at_exit handlers from the parent, eg
my code is closer to

   t = Thread.new{ socket.read; death_callback.call }

   ObjectSpace.define_finalizer(t){ socket.close }

   fork{
     at_exit{ exit! } # don't inherit from parent
                      # socket doesn't get closed here, even though t gets reaped
     exit
   }

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?

-a
-- 
my religion is very simple.  my religion is kindness. -- the dalai lama