Jump to content
Unity Insider Forum

Integer Wert wird bei Aufruf eines Threads einfach überschrieben


Kokujou

Recommended Posts

Yo!

Es macht mich wirklich fertig und ich habe so gar keine Ahnung was da los ist. Ich rufe einen Thread in einem for-loop auf:

for (int node = 0; node < StateTree[level].Count; node++)
{
	Thread temp = new Thread(() => BuildChildNodes(Turn, level, node));
	temp.Start();
	threads.Add(temp);
}

Der Wert ist ja am Anfang 0. Aber dann wenn ich in den Thread reingehe und mir den Wert ausgeben lasse ist er plötzlich 1!!! Und das schon am Anfang des Threads. Ich kann mir nur erklären dass aus irgendwelchen irrsinnigen Gründen die Referenz auf den Integer-Wert node übergeben wurde und wenn die for-Schleife dann weitergeht und zu 1 zählt (wo sie im 1. Durchlauf übrigens schon abbricht) verändert das dann aus irgendwelchen Gründen auch den Integer-Wert im Thread.

Aber das kann doch gar nicht sein! Was ist da los?!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Für mich ergibt das auch keinen Sinn.. ich hoffe jemand anders kann das genauer erklären.

 

Aber ich hatte mal ein sehr ähnliches Problem, als ich mit einem for-loop versucht habe UI-Buttons ein OnClick event zuzuteilen, mit der Zählvariable als Parameter.

Da  war der übergebene Parameter auch immer der 'letzte' Wert der Zählvariable.

 

Ich hab dann einfach die Zählvariable zwischengespeichert, und die dann als Parameter übergeben.

 

also

int tmpNode = node;

Thread temp = new Thread(() => BuildChildNodes(Turn, level, tmpNode));
 

vtl. funktioniert das auch hier..

Link zu diesem Kommentar
Auf anderen Seiten teilen

Der Wert der Variable node wird ausgewertet wenn der Thread beginnt und anfängt zu arbeiten. Da wir es hier mit einem Thread zu tun haben kann dies zu einem beliebigen Zeitpunkt passieren der auf jedem Fall in der Zukunft liegt, die Reihenfolge welcher der vielen Threads nun zuerst anfängt ist dabei nicht garantiert.

 

Was hier bei dir passiert ist dass du deine for Schleife in Thread 0 durchläufst. Diese for Schleife startet Thread 1 ... n. Die Threads fangen aber erst etwas später an zu laufen. Mit dem Ergebniss dass deine Zählvariable "node" von Thread 1 schon hoch gezählt wurde. Nun kommt es dass zB. Thread 1 anfängt zu arbeiten und den aktuellen Wert von "node" ausliest. Nun wurde "node" natürlich schon hochgezählt und somit hat es nicht mehr  den von dir gewünschten Wert.

 

Die Lösung wie man dieses Problem vermeidet ist ganz einfach: Deklariere eine temporäre Variable im Scope deiner for Schleife und verwende diese temporäre Variable anstatt "node". Die temporäre Variable wird in dein Lamda gehoistet anstatt von "node" und da du diese temporäre Variable nirgendwo sonst veränderst wird diese den Wert für dieses Lamda besitzen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das finde ich als Java-Entwickler echt interessant. Wenn man in Java eine Integer variable in eine Funktion übergibt, wird der Wert kopiert. In C# bekommt man anscheinend den Pointer. Oder ist das nur in diesem Spezialfall so?

Auf jeden Fall wird die Lösung von Mr 3d funktionieren.

Aber mal eine andere Frage:

Wieso willst du da was mit Threads machen? Das sieht für mich aus als würdest du mit Parallelität nur Probleme an dieser Stelle bekommen. Ich würde das eher ganz einfach alles nacheinander machen. Gerade wenn du noch Turn und Level verwendest (ich vermute mal das sind globale Variablen), und du dort irgendwas änderst, gibt es Überschneidungen im Zugriff bei den Threads.

Link zu diesem Kommentar
Auf anderen Seiten teilen

In C# wird auch nur der Wert kopiert, aber behind the scenes wird auch noch etwas anderes getan. Es wird eine versteckte Klasse generiert deren Instanz pro Methodenaufruf erstellt und weiterverwendet wird. In dieser Klasse werden nun alle Werte gehalten die für den Lambda Ausdruck relevant sind. In diesem Fall also die "node" Variable. Kurz und knackig:

for (int i = 0; i < 5; ++i)

  DoSomethingInANiceThread(() => Print(i));

 

 

Generiert behind the scenes folgendes:

 

internal class A

{

  public int i = 0;

}



for (A instance = new A(); instance.i < 5; ++instance.i)

  DoSomethingInANiceThread(() => Print(instance.i));

 

Mr 3D: Sorry, hatte ganz überlesen dass du sowas schon geschrieben hast.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...