2015-09-16 16 views
5

Ich habe Schwierigkeiten zu verstehen, warum das Multithreading keine Werte aktualisieren kann, bevor der Thread abgeschlossen ist. Hat der separate Thread eine eigene Kopie der Referenzen oder Werte?
Multithreading-Problem beim Aktualisieren des Werts

Wenn nicht, nach meinem Verständnis der Code unten sollte ordnungsgemäß funktionieren, wenn MyMethod genannt wird, aber oft ist es nicht Instanzen einiger MyType Objekte im Array erstellen, bevor die thread.IsAlive wird false:

class MyClass 
{ 
    static MyType[] obj = new MyType[Environment.ProcessorCount - 1]; 
    void MyMethod() 
    { 
     Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

     for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
     { 
      threads[i] = new Thread(() => FillObjects(i)); 
      threads[i].Priority = ThreadPriority.AboveNormal; 
      threads[i].Start(); 
     } 

     while (threads[i].Any(c => c.IsAlive)) 
     { 
      Thread.Sleep(50); 
     } 
    } 
    void FillObjects(int i) 
    { 
     obj[i] = new MyType(); 
     //perform actions with obj[i] to fill it with necessary values 
    } 
} 

Antwort

6

Sie müssen den Wert der Schleifenvariablen einer lokalen Variablen zuweisen. Andernfalls ist es möglich, dass die erste Ausführung von FillObjects(i) ausgeführt wird, nachdem i inkrementiert wurde, so dass FillObjects(0) nie aufgerufen wird und daher obj[0] niemals zugewiesen wird.

void MyMethod() 
{ 
    Thread[] threads = new Thread[Environment.ProcessorCount - 1]; 

    for (int i = 0; i < Environment.ProcessorCount - 1; i++) 
    { 
     int local = i; 
     threads[i] = new Thread(() => FillObjects(local)); 
     threads[i].Priority = ThreadPriority.AboveNormal; 
     threads[i].Start(); 
    } 

    while (threads.Any(c => c.IsAlive)) 
    { 
     Thread.Sleep(50); 
    } 
} 
+2

Guter Punkt. Wenn die erste Anweisung in 'FillObjects()' ein 'Thread.Sleep (1000) 'wäre, wäre wahrscheinlich nur' obj [Environment.ProcessorCount - 1] 'nicht null, weil die Schleife" i "bis zu ihrem Endwert inkrementiert hätte bevor das erste Objekt erstellt wird. Wenn man darüber nachdenkt, kann FillObjects() werfen, weil "i" tatsächlich in "Environment.ProcessorCount-1" inkrementiert wird, bevor die Schleife beendet wird und somit außerhalb von "obj" liegt. –

+0

Vielen Dank für die Antwort, in der Tat war das eines der Hauptprobleme, jetzt instanziiert es die Objekte richtig. Der Thread führt jedoch nicht alle Vorgänge ordnungsgemäß durch, bevor er beendet wird, und zwar nach dem Zufallsprinzip. Irgendwelche Vorschläge? – Almis

+0

Ich habe meinen eigenen logischen Fehler gefunden, jetzt funktioniert es richtig. – Almis

-1

Auf einem Multi-Prozessor-Rechner (den Sie haben müssen) sind Ergebnisse, die an einen Speicherort in einem Thread geschrieben wurden, aufgrund des Caching möglicherweise nicht in einem anderen Thread sichtbar. Verwenden Sie Thread.VolatileRead und Thread.VolatileWrite lesen, um "durch" den Cache zu lesen und zu schreiben.

Cf. the chapter on threading in c# 3.0 in a Nutshell für eine Erklärung. (Suchen Sie nach der Frage "Ist es möglich, dass die Wait-Methode" False "schreibt? Dieses Beispiel ist grundsätzlich Ihr Fall.)

+0

Aus Neugier: Was ist falsch oder nicht anwendbar von dem, was ich gesagt habe? –

+0

Obwohl nicht derjenige, der downvoted: Ich kann nicht an ein Szenario denken, das volatileRead/Write verwendet, um das obige Problem zu lösen. Das referenzierte Problem von C# in der Nussschale IMHO stimmt nicht oben genanntes Problem überein, und ich sehe keine Caching-Probleme, die volatile lösen würden. – Linky

+0

@Linky Hm. Es sind zwei Threads, die beide auf eine statische Variable zugreifen. Ein Thread hat "geschrieben" (angezeigt durch ein Ereignis später in diesem Thread). Der andere Thread liest den Wert, der aus der Perspektive des schreibenden Threads geschrieben wurde, und sieht den Schreibvorgang nicht. Sieht für mich sehr ähnlich aus wie das Szenario hier. –

Verwandte Themen