2010-12-19 13 views
44

Ich sehe online, dass es heißt, ich verwende myThread.Join();, wenn ich meinen Thread blockieren möchte, bis ein anderer Thread beendet. (Eines der Dinge, die ich nicht verstehe, ist, was passiert, wenn ich mehrere Threads habe).Multithreading: Wann würde ich ein Join verwenden?

Aber im Allgemeinen bekomme ich einfach nicht, wenn ich .Join() oder eine Bedingung verwenden würde, dass es nützlich ist. Kann mir bitte jemand erklären, dass ich ein Viertklässler bin? Sehr einfache Erklärung zu verstehen, wird meine Antwort erhalten.

Antwort

49

Lassen Sie uns das Lesen sagen Sie einige Worker-Threads starten wollen eine Art von Berechnung auszuführen, und dann etwas zu tun, danach mit allen Ergebnissen.

List<Thread> workerThreads = new List<Thread>(); 
List<int> results = new List<int>(); 

for (int i = 0; i < 5; i++) { 
    Thread thread = new Thread(() => { 
     Thread.Sleep(new Random().Next(1000, 5000)); 
     lock (results) { 
      results.Add(new Random().Next(1, 10)); 
     } 
    }); 
    workerThreads.Add(thread); 
    thread.Start(); 
} 

// Wait for all the threads to finish so that the results list is populated. 
// If a thread is already finished when Join is called, Join will return immediately. 
foreach (Thread thread in workerThreads) { 
    thread.Join(); 
} 

Debug.WriteLine("Sum of results: " + results.Sum()); 

Ach ja, und Zufall nicht so verwenden, hatte ich versucht, nur ein minimales, leicht verständlich Beispiel zu schreiben. Es ist nicht wirklich zufällig, wenn Sie neue zufällige Instanzen zu nah an der Zeit erstellen, da der Startwert auf der Uhr basiert.

+1

Sie müssen etwas hinzufügen wie 'int value = i;' in der Foor-Schleife, bevor du einen neuen Thread startest. Weil 'i' zunehmen kann, bevor ein Thread beginnt, und die Summe wird nicht deterministisch sein. –

8

Join wird hauptsächlich verwendet, wenn Sie warten müssen, dass ein Thread (oder eine Reihe von Threads) beendet wird, bevor Sie mit Ihrem Code fortfahren.

Aus diesem Grund ist auch besonders nützlich, wenn Sie Ergebnis von einer Thread-Ausführung sammeln müssen.

Gemäß dem Arafangion-Kommentar unten ist es auch wichtig, Threads beizutreten, wenn Sie nach dem Erstellen eines Threads einen Reinigungs-/Haushaltscode eingeben müssen.

+1

erwähnen, dass Sollten Dies kann beim Bereinigen eines Prozesses wichtig sein, der auf den Ausgang vorbereitet wird. – Arafangion

+0

@Arafangion: richtig! – Lorenzo

15

Im folgenden Code-Schnipsel, ruft der Hauptthread Join(), die es bewirkt, dass für alle gelaicht Threads warten zu beenden:

static void Main() 
{ 
    Thread regularThread = new Thread(ThreadMethod); 
    regularThread.Start(); 

    Thread regularThread2 = new Thread(ThreadMethod2); 
    regularThread2.Start(); 

    // Wait for spawned threads to end. 
    regularThread.Join(); 
    Console.WriteLine("regularThread returned."); 

    regularThread2.Join(); 
    Console.WriteLine("regularThread2 returned."); 
} 

Beachten Sie, dass, wenn Sie auch einen Thread aus dem Threadpool (mit QueueUserWorkItem hochgedreht zum Beispiel), Join würde nicht auf diesen Hintergrund-Thread warten. Sie müssen einen anderen Mechanismus implementieren, z. B. AutoResetEvent.

Für eine hervorragende Einführung in Threading, empfehle ich Joe Albahari kostenlosen Threading in C#

+1

danke für den Link zu kostenlos & wertvoll ebook –

7

Dies ist ein sehr einfaches Programm, um die Verwendung von Thread Join zu demonstrieren. Bitte folgen Sie meinen Kommentaren zum besseren Verständnis. Schreiben Sie dieses Programm so wie es ist.

using System; 
    using System.Threading; 


    namespace ThreadSample 
    { 
     class Program 
     { 
      static Thread thread1, thread2; 
      static int sum=0; 
      static void Main(string[] args) 
      { 
       start(); 
       Console.ReadKey(); 
      } 
      private static void Sample() { sum = sum + 1; } 
      private static void Sample2() { sum = sum + 10; } 

      private static void start() 
      {  
       thread1 = new Thread(new ThreadStart(Sample)); 
       thread2 = new Thread(new ThreadStart(Sample2)); 
       thread1.Start(); 
       thread2.Start(); 
      // thread1.Join(); 
      // thread2.Join(); 
       Console.WriteLine(sum); 
       Console.WriteLine(); 
      } 
     } 
} 

1.First Zeit läuft wie es (mit Kommentaren) ist: Dann wird 0 (Anfangswert) oder 1 (wenn Thread 1 beendet) oder 10 (oder Thread beendet)

2.Run mit Kommentar entfernen thread1.Join(): Ergebnis sollte immer mehr als 1 .because thread1.Join() gefeuert und Faden 1 sollte vor die Summe erhalten beendet werden.

3.Run mit Entfernen aller coments: Ergebnis sollte immer 11

0

Hinzufügen einer Verzögerung von 300ms in Methode "Probe" und eine Verzögerung von 400ms in "Sample2" von devopsEMK der Post würde es machen leichter zu verstehen.

Dies können Sie beobachten, indem Sie den Kommentar aus "thread1.Join();" Zeile, der Hauptthread wartet auf die "thread1" zu vervollständigen und erst nach bewegt sich.

0

Ein anderes Beispiel, wenn Ihr Arbeitsthread der liest aus einem Eingangsstrom lassen sagen, während die Lesemethode für immer laufen kann, und Sie wollen die irgendwie vermeiden - durch Timeout Anwendung eines anderen Watchdog-Thread mit:

// worker thread 
var worker = new Thread(() => { 
    Trace.WriteLine("Reading from stream"); 

    // here is the critical area of thread, where the real stuff happens 
    // Sleep is just an example, simulating any real operation 
    Thread.Sleep(10000); 

    Trace.WriteLine("Reading finished"); 
}) { Name = "Worker" }; 
Trace.WriteLine("Starting worker thread..."); 
worker.Start(); 

// watchdog thread 
ThreadPool.QueueUserWorkItem((o) => { 
    var timeOut = 5000; 
    if (!worker.Join(timeOut)) 
    { 
     Trace.WriteLine("Killing worker thread after " + timeOut + " milliseconds!"); 
     worker.Abort(); 
    } 
}); 
Verwandte Themen