2010-02-17 25 views
25

Tengo una aplicación de formularios de Windows que estoy comprobando todos los puertos serie para ver si un dispositivo en particular está conectado.C# Esperando múltiples hilos para terminar

Así es como hago girar cada hilo. El código siguiente ya está separado del hilo gui principal.

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

Quiero la siguiente línea de código que esperar hasta que todos los hilos han terminado. He intentado usar un t.join allí, pero eso simplemente los procesa linealmente.

+2

Estrictamente como una nota al margen y no es que haya preguntado al respecto, pero puede poner IsBackground = true en el hilo para que no bloquee el hilo principal si sale de la aplicación. – Patrick

Respuesta

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(); 
} 

Editar

que estaba buscando hacia atrás en esto, y me gusta la siguiente mejor

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

Esta es una solución buena y simple. Pero en mi caso System.Threading.Thread.Join() es visible en el informe de perfilado de instrumentación con un alto valor de tiempo exclusivo. A pesar de esto, esa es una gran manera. – Raph

2

almacenar los resultados de rosca en una lista después de que fueron generados e iterar la lista - durante la llamada de iteración únete a continuación. Aún te unes linealmente, pero debería hacer lo que quieras.

+0

cualquier código fuente completo al respecto? – Kiquenet

14

Use los AutoResetEvent y ManualResetEvent Clases:

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

¡Se ve excelente! – abatishchev

+2

auto.Set() debe estar en un bloque finally –

+3

¿Cuál es el punto del ManualResetEvent aquí? –

3

Se puede utilizar un CountDownLatch:

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(); 
    } 
} 

Ejemplo de cómo usarlo:

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

¿No está esto incluido en .NET como CountdownEvent? https://msdn.microsoft.com/en-us/library/system.threading.countdowvent(v=vs.110).aspx –

5

La forma más sencilla y segura de hacer esto es usar un CountdownEvent. Ver Albahari.

+0

Ah, no sabía que si el hilo había terminado, la unión volvería. Gracias por la corrección. – IamIC

Cuestiones relacionadas