Die Programmiersprache Ruby (German Edition)
Klassenmethode
Thread.abort_on_exception=
:
Thread.abort_on_exception = true
Wenn Sie möchten, dass nur die unbehandelte Exception eines bestimmten Threads zum Ende des Interpreters führt, nutzen Sie die Instanzmethode gleichen Namens:
t = Thread.new { ... }
t.abort_on_exception = true
9.9.2 Threads und Variablen
Ein zentraler Bestandteil von Threads ist, dass sie gemeinsam auf Variablen zugreifen können. Da Threads durch Blöcke definiert sind, haben sie Zugriff auf alle Variablen (lokale Variablen, Instanzvariablen, globale Variablen und so weiter), die sich im Gültigkeitsbereich des Blocks befinden:
x = 0
t1 = Thread.new do
# Dieser Thread kann die Variable x abfragen und setzen.
end
t2 = Thread.new do
# Dieser Thread fragt auch x ab und setzt es.
# Zudem kann er auf t1 und t2 zugreifen.
end
Wenn zwei oder mehr Threads auf dieselben Variablen konkurrierend lesend und schreibend zugreifen, müssen Sie dabei Vorsicht walten lassen. Wir werden mehr dazu sagen, wenn wir uns die Thread-Synchronisierung anschauen.
9.9.2.1 Thread-private Variablen
Variablen, die innerhalb des Blocks eines Threads definiert wurden, sind für diesen Thread privat und für andere Threads nicht sichtbar. Das ist einfach eine Konsequenz aus Rubys Gültigkeitsregeln für Variablen.
Wir wollen häufig, dass ein Thread seine eigene, private Kopie einer Variablen vorhält, so dass sich ihr Verhalten nicht ändert, wenn sich der Wert dieser Variablen ändert. Schauen Sie sich den folgenden Code an, der versucht, drei Threads zu erzeugen, die die Zahlen
1
,
2
und
3
ausgeben:
n = 1
while n <= 3
Thread.new { puts n }
n += 1
end
In manchen Situationen und in manchen Implementierungen funktioniert dieser Code eventuell wie erwartet und gibt die Zahlen
1
,
2
und
3
aus. In anderen Situationen oder anderen Implementierungen klappt das eventuell nicht. Es ist durchaus möglich (wenn die neu erzeugten Threads nicht sofort loslaufen), dass der Code zum Beispiel
4
,
4
und
4
ausgibt. Jeder Thread liest eine gemeinsame Kopie der Variable
n
, und der Wert dieser Variable ändert sich während der Ausführung der Schleife. Der vom Thread ausgegebene Wert hängt davon ab, wann der Thread im Verhältnis zum übergeordneten Thread läuft.
Um dieses Problem zu lösen, übergeben wir den aktuellen Wert von
n
an die Methode
Thread.new
und weisen den aktuellen Wert dieser Variable einem Blockparameter zu. Blockparameter sind für den Block privat (siehe aber „5.4.3 Blöcke und Gültigkeitsbereiche von Variablen“ wegen der Vorsichtsmaßnahmen), und diese private Variable wird nicht zwischen den Threads geteilt:
n = 1
while n <= 3
# Eine private Kopie des aktuellen Werts von n in x verwalten
Thread.new(n) {|x| puts x }
n += 1
end
Beachten Sie, dass man dieses Problem auch über einen Iterator statt mit einer
while
-Schleife lösen kann. In diesem Fall ist der Wert von
n
für den äußeren Block privat und ändert sich während der Ausführung des Blocks nicht:
1.upto(3) {|n| Thread.new { puts n }}
9.9.2.2 Thread-lokale Variablen
Einige der speziellen globalen Variablen von Ruby sind Thread-lokal : Sie können in unterschiedlichen Threads verschiedene Werte haben.
$SAFE
(siehe „10.5 Sicherheit“ ) und
$~
(siehe Tabelle 9.3 ) sind Beispiele dafür. Wenn also zwei Threads reguläre Ausdrücke parallel nutzen, sehen sie in
$~
unterschiedliche Werte, und wenn man in einem Thread ein Match ausführt, wird es nicht mit den Ergebnissen eines Matches in einem anderen Thread durcheinanderkommen.
Die Klasse
Thread
verhält sich ähnlich wie ein Hash. Sie definiert die Instanzmethoden
[]
und
[]=
, mit denen Sie beliebige Werte mit einem beliebigen Symbol in Verbindung bringen können. (Wenn Sie stattdessen einen String nutzen, wird dieser in ein Symbol umgewandelt. Anders als echte Hashes erlaubt die Klasse
Thread
als Schlüssel nur Symbole.) Die mit diesen Symbolen verbundenen Werte verhalten sich wie Thread-lokale Variablen. Sie sind nicht privat wie blocklokale Variablen, da jeder Thread solch einem Wert in einem beliebigen anderen Thread auslesen kann. Aber es sind auch keine gemeinsam genutzten Variablen, da jeder Thread seine eigene Version nutzen kann.
Stellen Sie sich als Beispiel vor, dass wir Threads zum Herunterladen von Dateien von einem Webserver erzeugt haben. Der Haupt-Thread wird den Fortschritt der Downloads verfolgen wollen. Dazu kann jeder Thread Folgendes tun:
Thread.current[:progress] = bytes_received
Der Haupt-Thread kann dann
Weitere Kostenlose Bücher