2012-05-06 11 views
7

Supponiamo di avere più thread tutto chiamando la stessa funzione:Più thread chiamando la stessa funzione

def foo 
    # do stuff ... 
end 

100.times do |i| 
    Thread.new do 
    foo 
    end 
end 

Se due o più thread sono attualmente all'interno di foo, fanno ogni azione le stesse variabili locali all'interno foo?

Questo riguarda la mia seconda domanda. I thread hanno frame di stack singoli o condividono frame di stack in un singolo processo? In particolare, quando più thread invocano foo e prima di foo restituisce, ci sono più copie di foo nello stack, ciascuna con le proprie variabili locali oppure c'è una sola copia di foo nello stack?

risposta

4

Sì, condividono le stesse variabili. Questo è un elemento chiave di Thread e va bene in un contesto di sola lettura, ma se scrivono su una di queste variabili, è necessario utilizzare un thread Mutex e synchronize, in modo che solo uno possa modificare una variabile in qualsiasi momento . A volte possono invocare un metodo che modifica i dati in modo indiretto, quindi è necessario conoscere il sistema completamente prima di decidere se è necessario sincronizzarsi o meno.

Per quanto riguarda la seconda domanda, se ho capito cosa stai chiedendo, hanno frame di stack singoli, ma sono ancora tutti condividendo gli stessi dati in memoria.

Il chiarire, nel seguente esempio, la variabile locale zipè condiviso da più thread, poiché è stato definito nell'ambito corrente (fili non cambiano portata, hanno appena iniziano una filettatura cilindrica separata di esecuzione nello scopo attuale).

zip = 42 

t = Thread.new do 
    zip += 1 
end 

t.join 

puts zip # => 43 

join qui mi salva, ma ovviamente non c'è nessun punto nel thread a tutti, se continuo che c'è. Sarebbe pericoloso se dovessi fare quanto segue:

zip = 42 

t = Thread.new do 
    zip += 1 
end 

zip += 1 

puts zip # => either 43 or 44, who knows? 

Questo è perché avete fondamentalmente due thread entrambi cercando di modificare zip allo stesso tempo. Ciò diventa evidente quando si accede alle risorse di rete o si aumentano i numeri ecc. Come sopra.

Nel seguente esempio, tuttavia, la variabile locale zip viene creato all'interno di un uno completamente nuovo ambito, così i due fili non sono effettivamente scrivendo alla stessa variabile contemporaneamente:

def foo 
    zip = 42 
    zip += 1 # => 43, in both threads 
end 

Thread.new do 
    foo 
end 

foo 

Ci sono gestiti due stack paralleli, ciascuno con le proprie variabili locali all'interno del metodo foo.

Il codice seguente, tuttavia, è pericoloso:

@zip = 42 # somewhere else 

def foo 
    @zip += 1 
end 

Thread.new do 
    foo 
end 

foo 

puts @zip # => either 43 or 44, who knows? 

Questo perché l'istanza variabile @zip è accessibile all'esterno del campo di applicazione della funzione foo, quindi entrambi i fili stiano accedendo allo stesso tempo.

Questi problemi di "due thread che cambiano gli stessi dati allo stesso tempo" vengono risolti utilizzando Mutex (blocchi) accuratamente posizionati attorno alle sezioni del codice che modificano la variabile.Il Mutex deve essere creato prima del prima del i thread vengono creati, perché nel caso di un Mutex, è (in base alla progettazione) fondamentale che entrambi i thread accedano allo stesso Mutex, per sapere se è bloccato o meno.

# somewhere else... 
@mutex = Mutex.new 
@zip = 42 

def foo 
    @mutex.synchronize do 
    @foo += 1 
    end 
end 

Thread.new do 
    foo 
end 

foo 

puts @zip # => 44, for sure! 

Se, quando il flusso di esecuzione raggiunge la linea Mutex#synchronize, si cerca di bloccare il mutex. Se ha successo, entra nel blocco e continua ad essere eseguito. Al termine del blocco, il mutex viene sbloccato di nuovo. Se il mutex è già bloccato, il thread attende finché non diventa di nuovo libero ... effettivamente è come una porta che solo una persona può attraversare alla volta.

Spero che questo chiarisca le cose.

+0

Potrebbe fornire un esempio di contesto di sola lettura? Se foo crea una variabile locale, non deve assegnargli qualcosa? –

+0

Quello che ho letto qui: http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html sotto l'argomento "Variabili del thread" suona diverso. O mi sto perdendo qualcosa. – alk

+1

Ah, ho frainteso. Se la funzione foo crea una variabile locale, va bene. Se crea una variabile di istanza, tuttavia, a cui è possibile accedere da altri thread, dovrebbe utilizzare un Mutex. Con "sola lettura", voglio semplicemente dire che nessuna variabile di istanza/variabile globale viene modificata. Le variabili locali vanno bene ... appartengono al thread corrente. – d11wtq

0

Le variabili locali, definite all'interno del metodo, non sono condivise. Ma è possibile che i thread accedano alle variabili di istanza dello stesso oggetto se è nell'ambito del blocco di thread.

Ad esempio:

def foobar 
    puts "Foo is defined!" if defined?(foo)=='local-variable' 
    foo = 5 
end 

sarebbe mai mettere la stringa se chiamato da più thread.

ma la seguente ha bisogno di un mutex da sincronizzare, in quanto si applicano condizioni di gara:

foo = {bar:5} 
def foobar(value) 
    value[:bar]+=5 
end 
15.times{|i| Thread.new{foobar foo}} 

Dopo questo, foo [: bar] potrebbe contenere un valore di 35, dal momento che ogni chiamata di foobar, cambia un valore all'interno dell'hash, foo.

Problemi correlati