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.
Potrebbe fornire un esempio di contesto di sola lettura? Se foo crea una variabile locale, non deve assegnargli qualcosa? –
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
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