2010-02-27 2 views
8

Первый один:Два вопроса, связанные с Руби нити

  • как я могу создать тему, которая не запускается правильно away.If я использую initialize без блока исключение получает поднятым.

  • Как я могу подклассы Thread, так что я могу добавить некоторые пользовательские атрибуты, но сохранить ту же функциональность, что и базовый класс Thread? Я также хотел бы не использовать метод initialize(&block) для этого.

Чтобы лучше проиллюстрировать это:

Для первого вопроса:

x = Thread.new 
x.run = { 
    # this should happen inside the thread 
} 
x.start # i want to manually start the thread 

Для второго:

x = MyThread.new 
x.my_attribute = some_value 
x.run = { 
    # this should happen when the thread runs 
} 
x.start 

Я искал что-то похожее на это. Надеюсь, ты поможешь.

+3

Почему вы не можете просто заменить «x.start» на 'x = Thread.new {etc}'? –

ответ

11

Вопрос 1

Исследование источника МРТ 1.8.7 не выявили очевидный способ, чтобы начать нить в «остановленном» состояние.

Что вы можете сделать, это иметь блок потока на заблокированном мьютексе, а затем разблокировать мьютекс, когда вы хотите, чтобы поток был включен.

#!/usr/bin/ruby1.8 

go = Mutex.new 
go.lock 
t = Thread.new do 
    puts "Thread waiting to go" 
    go.lock 
    puts "Thread going" 
end 
puts "Telling the thread to go" 
go.unlock 
puts "Waiting for the thread to complete" 
t.join 

# => Thread waiting to go 
# => Telling the thread to go 
# => Thread going 
# => Waiting for the thread to complete 

Вопрос 2 (Рода)

вы знаете, вы можете передать аргументы вашего потока ли? Все, что передается Thread.new получает передается через блок, как аргументы:

#!/usr/bin/ruby1.8 

t = Thread.new(1, 2, 3) do |a, b, c| 
    puts "Thread arguments: #{[a, b, c].inspect}" 
    # => Thread arguments: [1, 2, 3] 
end 

Есть также «нить локальные переменные,» а за нить ключ/значение магазина. Используйте Thread#[]=, чтобы установить значения, и Thread#[], чтобы вернуть их. Вы можете использовать строку или символы в качестве ключей.

#!/usr/bin/ruby1.8 

go = Mutex.new 
go.lock 
t = Thread.new(1, 2, 3) do |a, b, c| 
    go.lock 
    p Thread.current[:foo] # => "Foo!" 
end 
t[:foo] = "Foo!" 
go.unlock 
t.join 

Вопрос 2, Действительно

Вы можете делать то, что вы хотите сделать. Это большая работа, особенно когда обычный способ обработки потоков настолько прост. Вы должны взвесить все плюсы и минусы:

#!/usr/bin/ruby1.8 

require 'forwardable' 

class MyThread 

    extend Forwardable 

    def_delegator :@thread, :join 
    def_delegator :@thread, :[]= 
    def_delegator :@thread, :[] 

    def initialize 
    @go = Mutex.new 
    @go.lock 
    @thread = Thread.new do 
     @go.lock 
     @stufftodo.call 
    end 
    end 

    def run(&block) 
    @stufftodo = block 
    @go.unlock 
    @thread.join 
    end 

end 

t = MyThread.new 
t[:foo] = "Foo!" 
t.run do 
    puts Thread.current[:foo] 
end 
t.join 

# => "Foo!" 
+0

Спасибо, что нашли время, чтобы написать этот подробный ответ. Я пошел с переменными потока, используя метод Thread.current. Ваш ответ был очень интересным. Благодаря! – Geo

3
stuff_to_do = lambda do 
    # this happens in the thread 
end 

x = Thread.new(&stuff_to_do) 
+0

Как создать поток без его запуска? – Geo

+0

Что делает амперсанд? Кодекс разбивается без него, но я хочу понять синтаксис. –

2

Игнорируйте example from Ruby-Doc 1.8.7, потому что он содержит условие гонки. См Ruby 2 example, или что-то вроде следующего:

Я испытал это в Рубине 2.0 и Ruby, 1.8.7, и я обнаружил, что вызов #wakeup не было достаточно 1.8.7' : Я должен был назвать #run. Кажется, что работает следующее:

t = Thread.new { Thread.stop; puts "HELLO" } 
until t.stop?; end # ensure thread has actually stopped before we tell it to resume 
t.run 
+3

Это условие гонки. Если t.run происходит до Thread.stop, поток никогда не пройдет мимо этого. – ChrisPhoenix

+0

Крис прав. Я на самом деле просто столкнулся с этим условием. Я обновил сообщение с оживленным ожиданием, чтобы избежать гонки. – Patrick

Смежные вопросы