Thread.current.parent and Thread.current.ancestors


#1

can anyone see issues with this:

harp:~ > cat a.rb
class Thread
class << self
alias_method “new”, “new”

 def new *a, &b
   parent = Thread.current

   __new__(*a) do |*a|
     Thread.current.parent = parent
     b.call *a
   end
 end

end

def parent
self[‘parent’]
end

def parent= parent
self[‘parent’] = parent
end

def ancestors
list = [t = self]
while((t = t.parent))
list << t
end
list
end
end

Thread.new{ Thread.new{ Thread.new{ sleep 2; p Thread.current.ancestors
} } }

STDIN.gets

harp:~ > ruby a.rb
[#<Thread:0xb75d2264 run>, #<Thread:0xb75d2354 dead>,
#<Thread:0xb75d2444 dead>, #<Thread:0xb75df900 sleep>]

it’s hard to wrap my head around, but even GC seems like it’d be fine -
the
child, upon death, will allow the parent to be freed, and so on.

-a


#2

It doesn’t work with Thread#start (==fork)…

Thread#start doesn’t reuse Thread.new. Neither does
rb_thread_create(), which is used in e.g. TK.

All three methods (new, start/fork and rb_thread_create()) come
together in rb_thread_alloc(). That’s the place where the
parent should be set. The problem is that you can’t redefine
rb_thread_alloc() in Ruby… ;[

I really like this Thread.current.parent or Thread.parent.
There’s at least one place where I really, really need it
myself… Something for Ruby 1.8.6?.. ;]

gegroet,
Erik V. - http://www.erikveen.dds.nl/


#3

Using new_with_parent (see below) has two advantages:

  • By calling new_with_parent, you’re saying: Yes, I know that
    parent doesn’t work for all threads.

  • Thread#parent doesn’t return nil for “unpatched” threads,
    since it doesn’t exist in the first place.

You can achieve the same by subclassing Thread.

Disadvantage:

  • You can only ask for parents of your own threads. You can’t
    ask for a parent of e.g. a DRb thread, since those aren’t
    patched.

gegroet,
Erik V. - http://www.erikveen.dds.nl/


class Thread
def self.new_with_parent(*args, &block)
parent = Thread.current

 self.new do
   define_method :parent do
     parent
   end

   block.call(*args)
 end

end
end


#4

On Fri, 16 Feb 2007, Erik V. wrote:

It doesn’t work with Thread#start (==fork)…

Thread#start doesn’t reuse Thread.new. Neither does
rb_thread_create(), which is used in e.g. TK.

All three methods (new, start/fork and rb_thread_create()) come
together in rb_thread_alloc(). That’s the place where the
parent should be set. The problem is that you can’t redefine
rb_thread_alloc() in Ruby… ;[

hrrrm. good point, this is the best i’ve come up with:

harp:~ > cat a.rb
class Thread
class << self
alias_method “new”, “new”
def new *a, &b
child ‘new’, *a, &b
end
alias_method “start”, “start”
def start *a, &b
child ‘start’, *a, &b
end
private
def child as, *a, &b
parent = Thread.current
send(as, *a) do |*a|
Thread.current.parent = parent
b.call *a
end
end
end
def parent
self[‘parent’]
end
def parent= parent
self[‘parent’] = parent
end
def ancestors
return self[‘ancestors’] if self[‘ancestors’]
list = [t = self]
while((t = t.parent))
list << t
end
self[‘ancestors’] = list
end
end

Thread.new{ Thread.new{ Thread.new{ sleep 0.42 and p [Thread.current,
Thread.current.ancestors] } } }
Thread.start{ Thread.start{ Thread.start{ sleep 0.42 and p
[Thread.current, Thread.current.ancestors] } } }

STDIN.gets

harp:~ > ruby a.rb
[#<Thread:0xb75cc0f8 run>, [#<Thread:0xb75cc0f8 run>,
#<Thread:0xb75cc24c dead>, #<Thread:0xb75cc3a0 dead>,
#<Thread:0xb75da748 sleep>]]
[#<Thread:0xb75cc508 run>, [#<Thread:0xb75cc508 run>,
#<Thread:0xb75cc65c dead>, #<Thread:0xb75cc7b0 dead>,
#<Thread:0xb75da748 sleep>]]

I really like this Thread.current.parent or Thread.parent.
There’s at least one place where I really, really need it
myself… Something for Ruby 1.8.6?.. ;]

RCR?

-a