2010-02-17 30 views
25

Ich habe eine Windows Forms App, die ich alle seriellen Schnittstellen überprüfen, um festzustellen, ob ein bestimmtes Gerät verbunden ist.C# Warten auf mehrere Threads zu beenden

So spinne ich jeden Thread ab. Der folgende Code ist bereits vom Hauptgui-Thread abgespalten.

foreach (cpsComms.cpsSerial ser in availPorts) 
{ 
    Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev)); 
    t.Start((object)ser);//start thread and pass it the port 
} 

Ich möchte die nächste Codezeile warten, bis alle Threads beendet sind. Ich habe versucht, eine t.join dort zu verwenden, aber das verarbeitet sie nur linear.

+2

Streng als eine Randnotiz und nicht, dass Sie danach gefragt, aber Sie können IsBackground = True auf den Thread setzen, um nicht den Haupt-Thread zu blockieren, wenn Sie die Anwendung beenden. – Patrick

Antwort

34
List<Thread> threads = new List<Thread>(); 
foreach (cpsComms.cpsSerial ser in availPorts) 
{ 
    Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev)); 
    t.Start((object)ser);//start thread and pass it the port 
    threads.Add(t); 
} 
foreach(var thread in threads) 
{ 
    thread.Join(); 
} 

bearbeiten

Ich war wieder auf diese Suche, und Ich mag die bessere folgende

availPorts.Select(ser => 
     { 
      Thread thread = new Thread(lookForValidDev); 
      thread.Start(ser); 
      return thread; 
     }).ToList().ForEach(t => t.Join()); 
+0

Dies ist eine gute und einfache Lösung. Aber in meinem Fall ist System.Threading.Thread.Join() im Instrumentierungs-Profiling-Bericht mit einem hohen exklusiven Zeitwert sichtbar. Trotzdem ist das ein wirklich toller Weg. – Raph

2

Speichern Sie die Themen-Ergebnisse in einer Liste, nachdem sie wurden hervorgebracht und die Liste iterieren - während der Iteration rufen Sie dann Join auf. Sie verbinden sich immer noch linear, aber es sollte tun, was Sie wollen.

+0

einen vollständigen Quellcode darüber? – Kiquenet

14

Verwenden Sie die Autoreset und Manual Klassen:

private ManualResetEvent manual = new ManualResetEvent(false); 
void Main(string[] args) 
{ 
    AutoResetEvent[] autos = new AutoResetEvent[availPorts.Count]; 

    manual.Set(); 

    for (int i = 0; i < availPorts.Count - 1; i++) 
     { 

     AutoResetEvent Auto = new AutoResetEvent(false); 
     autos[i] = Auto; 

     Thread t = new Thread(() => lookForValidDev(Auto, (object)availPorts[i])); 
     t.Start();//start thread and pass it the port 

    } 
    WaitHandle.WaitAll(autos); 
    manual.Reset(); 

} 


void lookForValidDev(AutoResetEvent auto, object obj) 
{ 
    try 
    { 
     manual.WaitOne(); 
     // do something with obj 
    } 
    catch (Exception) 
    { 

    } 
    finally 
    { 
     auto.Set(); 
    } 


} 
+0

Sieht ausgezeichnet aus! – abatishchev

+2

auto.Set() sollte in einem endgültigen Block sein –

+3

Was ist der Sinn des ManualResetEvent hier? –

3

Sie einen CountDownLatch verwenden können:

public class CountDownLatch 
{ 
    private int m_remain; 
    private EventWaitHandle m_event; 

    public CountDownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 

Beispiel wie man es benutzt:

void StartThreads 
{ 
    CountDownLatch latch = new CountDownLatch(availPorts.Count); 

    foreach (cpsComms.cpsSerial ser in availPorts) 
    { 
     Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev)); 

     //start thread and pass it the port and the latch 
     t.Start((object)new Pair(ser, latch)); 

    } 

    DoSomeWork(); 

    // wait for all the threads to signal 
    latch.Wait(); 

    DoSomeMoreWork(); 
} 

// In each thread 
void NameOfRunMethod 
{ 
    while(running) 
    { 
     // do work 
    } 

    // Signal that the thread is done running 
    latch.Signal(); 
} 
+0

Ist dies nicht in .NET als CountdownEvent enthalten? https://msdn.microsoft.com/en-us/library/system.threading.countdownevent(v=vs.110).aspx –

5

Die einfachste und sicherste Weg, um Tun Sie dies, um einen CountdownEvent zu verwenden. Siehe Albahari.

+0

Ah, ich wusste nicht, dass der Join zurückkehren würde, wenn der Thread beendet wurde. Danke für die Korrektur. – IamIC

Verwandte Themen