ruby Thread#allocate TypeError

时间:2013-10-03 15:41:16

标签: ruby multithreading

我正在详细研究Thread类。基本上,我一直在寻找一种优雅的机制,允许在创建线程时继承线程局部变量。例如,我想要创建的功能将确保

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

=> “酒吧”

即。一个线程将继承它的调用线程的线程局部变量

所以我想到了重新定义Thread.new的想法,这样我就可以添加一个额外的步骤来将线程局部变量从当前线程复制到新线程中。像这样:

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

但是当我尝试这个时,我收到以下错误:

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

我认为,由于Thread是Object的子类,它应该有一个有效的#allocate方法。情况不是这样吗?

有没有人对此有深入的了解,以及如何实现我正在寻找的功能。

提前致谢

史蒂夫

3 个答案:

答案 0 :(得分: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

use_case.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"

答案 1 :(得分: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

答案 2 :(得分:0)

我最近在寻找同样的东西,并且能够想出以下答案。请注意,我知道以下是一种黑客行为,不推荐使用,但为了回答有关如何更改 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