2009-07-31 17 views
5

Estoy escribiendo un programa donde normalmente comienzo cinco hilos. Los hilos vuelven en un orden no determinado. Cada hilo está llamando a un método que devuelve una lista.Hilos que devuelven datos en .NET

que estoy haciendo esto:

var masterList = List<string>();  
foreach (var threadParam in threadParams) 
{ 
    var expression = threadParam ; 
    ThreadStart sub =() => MyMethod(expressions); 
    var thread = new Thread(sub) 
    { 
     Name = expression 
    }; 

    listThreads.Add(thread); 
    thread.Start(); 
} 

var abort = true; 
while (abort) //Wait until all threads finish 
{ 
    var count = 0; 
    foreach (var list in listThreads) 
    { 
     if (!list.IsAlive) 
     { 
      count++; 
     } 
    } 

    if (count == listThreads.Count) 
    { 
     abort = false; 
    } 
} 

Así que aquí está el problema:

Cada hilo cuando se termina devuelve una lista me gustaría añadir el MasterList declaró anteriormente.

¿Cómo podría uno hacer esto?

También sé que debe haber una mejor manera que a continuación de esperar a que todos los hilos para terminar

var abort = true; 
while (abort) //Wait until all threads finish 
{ 
    var count = 0; 
    foreach (var list in listThreads) 
    { 
     if (!list.IsAlive) 
     { 
      count++; 
     } 
    } 

    if (count == listThreads.Count) 
    { 
     abort = false; 
    } 
} 

Respuesta

14

Utilice un WaitHandle


He aquí un ejemplo:

using System; 
using System.Threading; 

class ThreadSleeper 
{ 
    int seconds; 
    AutoResetEvent napDone = new AutoResetEvent(false); 

    private ThreadSleeper(int seconds) 
    { 
     this.seconds = seconds; 
    } 

    public void Nap() 
    { 
     Console.WriteLine("Napping {0} seconds", seconds); 
     Thread.Sleep(seconds * 1000); 
     Console.WriteLine("{0} second nap finished", seconds); 
     napDone.Set(); 
    } 

    public static WaitHandle DoSleep(int seconds) 
    { 
     ThreadSleeper ts = new ThreadSleeper(seconds); 
     Thread thread = new Thread(new ThreadStart(ts.Nap)); 
     thread.Start(); 
     return(ts.napDone); 
    } 
} 

public class OperationsThreadsWaitingwithWaitHandle 
{ 
    public static void Main() 
    { 
     WaitHandle[] waits = new WaitHandle[2]; 
     waits[0] = ThreadSleeper.DoSleep(8); 
     waits[1] = ThreadSleeper.DoSleep(4); 

     Console.WriteLine("Waiting for threads to finish"); 
     WaitHandle.WaitAll(waits); 
     Console.WriteLine("Threads finished"); 
    } 
} 

enlaces que puedes visitar:

+1

La misma idea que la mía ... pero una respuesta mucho mejor :( –

0

Mira la clase WaitHandle y la WaitHandle.WaitAll (he utilizado la clase ManualResetEvent en algunas de mi código para WaitHandle pero es solo por un ejemplo. No sé si hay algo mejor para su situación). Apague los cinco hilos, déles una referencia a su lista maestra, bloquee esta lista cuando la agregue y luego complete la señal. Use WaitHandle.WaitAll para bloquear hasta que los cinco hayan indicado la finalización.

2

La mejor manera sería hacer que cada hilo sea su propio objeto. No te entremezcles con otros objetos, todo lo que haces es construirlo (pasando las variables), agregarte como oyente e iniciarlo.

Cuando está hecho, almacena los valores en una variable miembro y notifica a su oyente.

Su oyente puede recuperar los valores en el ocio.

El acceso directo obvio, la devolución de los valores directamente al oyente, obras, sino que puede encontrar esta versión más flexible después (y realmente no mucho más código)

1

Por supuesto, también puede usar delegados regulares y APM.

Tenga en cuenta que el patrón que describe normalmente se describe como Future, un trabajo en segundo plano que promete devolver algo más adelante (un retorno de la inversión, si es posible).

Aquí hay un breve ejemplo, en forma de un programa de consola.

Salida:

sequential: 3224 ms 
parallel: 2074 ms 

Por supuesto, ya que no estoy construyendo las discusiones explícitas, lo dejo al sistema de subprocesos de averiguar cuántos hilos para ejecutar en paralelo.

También hay disposiciones para ser informados de cuándo se han completado los hilos de fondo, a través de un método de devolución de llamada, así como el apoyo WaitHandle de comprobar de forma explícita y esperando con tiempo de espera, etc.

Y la fuente:

using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Diagnostics; 

namespace SO1215227 
{ 
    public class Program 
    { 
     public static void Main() 
     { 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      var list1 = Sequence(1, 100); 
      var list2 = Sequence(101, 200); 
      var list3 = Sequence(201, 300); 
      sw.Stop(); 
      Console.Out.WriteLine("sequential: " + sw.ElapsedMilliseconds + " ms"); 
      sw.Reset(); 

      Func<Int32, Int32, List<Int32>> listProducer = Sequence; 
      sw.Start(); 
      var list1Background = listProducer.BeginInvoke(1, 100, null, null); 
      var list2Background = listProducer.BeginInvoke(101, 200, null, null); 
      var list3Background = listProducer.BeginInvoke(201, 300, null, null); 

      list1 = listProducer.EndInvoke(list1Background); 
      list2 = listProducer.EndInvoke(list2Background); 
      list3 = listProducer.EndInvoke(list3Background); 
      sw.Stop(); 
      Console.Out.WriteLine("parallel: " + sw.ElapsedMilliseconds + " ms"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 

     private static List<Int32> Sequence(Int32 from, Int32 to) 
     { 
      List<Int32> result = new List<Int32>(); 
      for (Int32 index = from; index <= to; index++) 
      { 
       result.Add(index); 
       Thread.Sleep(10); // simulate I/O wait 
      } 
      return result; 
     } 
    } 
} 
Cuestiones relacionadas