2010-02-27 7 views
8

Pierwszy:dwa pytania związane z Ruby podaje

  • Jak mogę utworzyć wątku, który nie rozpoczyna się away.If używam initialize bez bloku wyjątek zostanie podniesiony.

  • W jaki sposób mogę utworzyć podklasę wątku, aby móc dodawać niestandardowe atrybuty, ale zachować tę samą funkcjonalność co podstawowa klasa wątków? Nie chciałbym też używać do tego metody initialize(&block).

Aby lepiej zilustrować następująco:

Na pierwsze pytanie:

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

Na drugi:

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

szukam coś podobnego do tego. Mam nadzieję, że możesz pomóc.

+3

Dlaczego nie możesz "tylko" zastąpić 'x.start' z' x = Thread.new {} 'etc? –

Odpowiedz

11

Pytanie 1

Badanie MRI 1.8.7 źródła nie ujawniły oczywisty sposób rozpocząć wątek w "zatrzymany" państwa.

Co możesz zrobić, to zablokować gwint na zablokowanym muteksie, a następnie odblokować muteks, gdy chcesz, aby wątek się poruszał.

#!/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 

Pytanie 2 (rodzaj)

Czy wiesz, że można przekazywać argumenty do wątku? Wszystko zostanie przekazane do Thread.new przepuszcza jako argumenty blokowych:

#!/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 

Istnieją również „nić” zmienne lokalne, sklep per-thread klucz/wartość. Użyj Thread#[]=, aby ustawić wartości, i Thread#[], aby je odzyskać. Możesz użyć ciągu lub symboli jako kluczy.

#!/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 

Pytanie 2, Naprawdę

Możesz robić, co chcesz zrobić. To dużo pracy, zwłaszcza gdy zwykły sposób obsługi wątków jest tak prosty. Będziesz musiał zważyć plusses i minusy:

#!/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

Dziękujemy za poświęcenie czasu na napisanie tej szczegółowej odpowiedzi. Wybrałem zmienne wątku, używając metody 'Thread.current'. Twoja odpowiedź była bardzo interesująca. Dzięki! – Geo

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

x = Thread.new(&stuff_to_do) 
+0

Jak utworzyć wątek bez jego uruchamiania? – Geo

+0

Czym zajmują się ampersand? Kod łamie się bez niego, ale chcę zrozumieć składnię. –

2

Zignoruj ​​example from Ruby-Doc 1.8.7 ponieważ zawiera warunek wyścigu. Zobacz Ruby 2 example, lub coś podobnego, co następuje:

Testowałem to w Ruby 2.0 i Ruby 1.8.7, i stwierdziliśmy, że nazywając #wakeup było mało w 1.8.7' Musiałem zadzwonić #run. Poniższa wydaje się działać w obie:

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

To ma stan wyścigu. Jeśli t.run ma miejsce przed Thread.stop, wątek nigdy go nie ominie. – ChrisPhoenix

+0

Chris ma rację. Właśnie natknąłem się na ten stan. Zaktualizowałem post z zapracowanym czekaniem, aby uniknąć wyścigu. – Patrick

Powiązane problemy