3

I was looking in detail at the Thread class. Basically, I was looking for an elegant mechanism to allow thread-local variables to be inherited as threads are created. For example the functionality I am looking to create would ensure that

Thread.new do
   self[:foo]="bar"
   t1=Thread.new { puts self[:foo] }
end

=> "bar"

i.e. a Thread would inherit it's calling thread's thread-local variables

So I hit upon the idea of redefining Thread.new, so that I could add an extra step to copy the thread-local variables into the new thread from the current thread. Something like this:

class Thread
  def self.another_new(*args)
    o=allocate
    o.send(:initialize, *args)
    Thread.current.keys.each{ |k| o[k]=Thread.current[k] }
    o
  end
end

But when I try this I get the following error:

:in `allocate': allocator undefined for Thread (TypeError)

I thought that as Thread is a subclass of Object, it should have a working #allocate method. Is this not the case?

Does anyone have any deep insight on this, and on how to achieve the functionality I am looking for.

Thanks in advance

Steve

4

3 回答 3

1
Thread.new do
  Thread.current[:foo]="bar"
    t1=Thread.new(Thread.current) do |parent|
    puts parent[:foo] ? parent[:foo] : 'nothing'
  end.join
end.join 

#=> bar

更新:

在 irb 中试试这个:

thread_ext.rb

class Thread
  def self.another_new(*args)
    parent = Thread.current
    a = Thread.new(parent) do |parent|
      parent.keys.each{ |k| Thread.current[k] = parent[k] }
      yield
    end
    a
  end
end

用例.rb

A = Thread.new do
  Thread.current[:local_a]="A"
  B1 =Thread.another_new do
    C1 = Thread.another_new{p Thread.current[:local_a] }.join
  end

  B2 =Thread.another_new do
    C2 = Thread.another_new{p Thread.current[:local_a] }.join
  end

  [B1, B2].each{|b| b.join }
end.join

输出

"A"
"A"
于 2013-10-03T16:23:49.057 回答
0

这是基于@CodeGroover 建议的修订答案,带有一个简单的单元测试工具

分机/thread.rb

class Thread
  def self.inherit(*args, &block)
    parent = Thread.current
    t = Thread.new(parent, *args) do |parent|
      parent.keys.each{ |k| Thread.current[k] = parent[k] }
      yield *args
    end
    t
  end
end

测试/thread.rb

require 'test/unit'
require 'ext/thread'

class ThreadTest < Test::Unit::TestCase
  def test_inherit
    Thread.current[:foo]=1
    m=Mutex.new
    
    #check basic inheritence
    t1= Thread.inherit do 
      assert_equal(1, Thread.current[:foo])
    end
      
    #check inheritence with parameters - in this case a mutex
    t2= Thread.inherit(m) do |m|
      assert_not_nil(m)
      m.synchronize{ Thread.current[:bar]=2 }
             
      assert_equal(1, Thread.current[:foo])
      assert_equal(2, Thread.current[:bar])
      
      sleep 0.1 
    end
      
    #ensure t2 runs its mutexs-synchronized block first
    sleep 0.05
    
    #check that the inheritence works downwards only - not back up in reverse
    m.synchronize do
      assert_nil(Thread.current[:bar])
    end
    
    [t1,t2].each{|x| x.join }
        
  end
  
end
于 2013-10-04T10:43:46.310 回答
0

我最近在寻找同样的东西,并能够提出以下答案。注意我知道以下是一个 hack 并且不推荐,但是为了回答关于如何更改Thread.new功能的具体问题,我做了如下操作:

class Thread
  class << self
    alias :original_new :new

    def new(*args, **options, &block)
      original_thread = Thread.current
      instance = original_new(*args, **options, &block)
      original_thread.keys.each do |key|
        instance[key] = original_thread[key]
      end
      instance
    end
  end
end
于 2021-01-21T12:55:13.643 回答