2016-07-11 7 views
1

Im folgenden Beispiel scheint es, dass der Index i der for-Schleife, die durch jeden Thread unabhängig modifiziert ist auf fremde Werte i führenden (Multiples, auch Werte größer als System.Environment.ProcessorCount-1) in DoWork_Threaded()Threading in C#: Wie wird der Loop-Index Thread-sicher gehalten?

Wie werden multithreaded Schleifen richtig in C# gemacht?

// Prepare all threads 
Thread[] threads = new Thread[System.Environment.ProcessorCount]; 

// Start all threads 
for (int i = 0; i < System.Environment.ProcessorCount; i++) 
{ 
    threads[i] = new Thread(() => DoWork_Threaded(i)); 
    threads[i].Start(); 
} 

// Wait for completion of all threads 
for (int i = 0; i < System.Environment.ProcessorCount; i++) 
{ 
    threads[i].Join(); 
} 
+0

Vielen Dank für Ihre Antwort, aber wie würde dies mit dem Index ich helfen? PS: Es funktioniert auch nicht. –

+0

versuchen, den Wert innerhalb der Schleife zu kopieren 'int a = i;' dann 'DoWork_Threaded (a);' – user3185569

+2

Für einige Erklärung, warum Ihr Code sich verhält, können Sie https://blogs.msdn.microsoft.com/ lesen ericlippert/2009/11/12/closing-over-the-loop-variabel-als-schädlich /. Es ist auch völlig unabhängig von Threading. Irgendwelche Schließungs-Schleifen-Variablen können das von Ihnen beschriebene Verhalten verursachen. – Dirk

Antwort

5

Erstens, anstatt Ihren eigenen Thread-Scheduling-Dienst zu rollen, warum nicht die parallele Bibliothek der Aufgabe verwenden? Es verfügt bereits über eine Logik, die die Anzahl der Prozessoren bestimmt, auf die Threads geplant werden sollen.

Um Ihre eigentliche Frage zu beantworten, sind Sie Schließen über eine Schleife Variable. Siehe meinen Artikel darüber, warum das ist falsch:

https://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/

Kurz: i ist eine Variable und Variablen ändern. Wenn Ihr Lambda ausgeführt wird, wird es mit dem aktuellen Wert von i ausgeführt, nicht den Wert, den es beim Erstellen des Delegaten hatte.

+0

Danke, dass Sie mich auf die TPL hingewiesen haben, was ziemlich nett ist. In meinem Fall haben wir jedoch viele (Millionen, Think Image Pixel) Elemente, die manuell über alle Kerne verteilt verarbeitet werden. Obwohl dies scheint fehleranfällig im Vergleich zur Verwendung von Parallel.For, es ist auch viel schneller. Ich weiß nicht, wie Parallel.For die Arbeit verteilt, aber ich nehme an, dies liegt an dem Overhead der Erstellung von viel mehr Threads ... vielleicht sogar für jedes Element? –

+0

Gibt es eine Möglichkeit, der TPL in einem solchen Fall (Millionen von Elementen in Parallel.Für eine Schleife) zu sagen (im Beispielfall von 4 Kernen) Core 1 für das erste Quartal, Core 2 für das zweite Quartal und so weiter zu verwenden? –

+0

@ares_games: Dies ist eine Frage-Antwort-Seite; Das klingt nach einer guten Frage, die du hier oder noch besser auf der Spieleseite posten kannst. –

3

Die Verwendung lokaler Variablen mit anonymen Methoden und Threads kann schwierig sein. Sie müssen den Wert kopieren, die durch die anonyme Methode verwendet wird, wie es sich verändert:

for (int i = 0; i < System.Environment.ProcessorCount; i++) 
{ 
    int a = i; 
    threads[i] = new Thread(() => DoWork_Threaded(a)); 
    threads[i].Start(); 
} 

Dies macht die Ausgabe rational auf meiner Maschine.