2009-07-31 10 views
5

Sto scrivendo un programma in cui in genere avvio cinque thread. I thread ritornano in un ordine non determinato. Ogni thread chiama un metodo che restituisce una lista.Thread che restituiscono dati in .NET

sto facendo questo:

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

Così qui è il problema:

Ogni thread quando termina restituisce una lista vorrei aggiungere il MasterList dichiarato in precedenza.

come si potrebbe andare su questo?

Inoltre so che ci deve essere un modo migliore di sotto di attesa per tutte le discussioni per finire

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

risposta

14

Utilizzare un WaitHandle


Ecco un esempio:

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

Link a controllare:

+1

La stessa idea del mio ... ma un modo migliore per rispondere :( –

0

Partenza classe WaitHandle e il WaitHandle.WaitAll (ho usato la classe ManualResetEvent in alcuni dei il mio codice per WaitHandle ma è solo da un esempio. Non so se c'è qualcosa di meglio per la tua situazione). Spegni tutti e cinque i thread, dai loro un riferimento alla tua lista master, blocca questo elenco quando lo aggiungi, quindi segnala il completamento. Usa WaitHandle.WaitAll per bloccare finché tutti e cinque non hanno segnalato il completamento.

2

Il modo migliore sarebbe quello di rendere ogni filo è proprio oggetto. Non avere alcuna mescolanza con altri oggetti, tutto ciò che fai è costruirlo (passare le variabili), aggiungerti come ascoltatore e avviarlo.

Al termine, memorizza i valori in una variabile membro e notifica al listener.

L'ascoltatore può recuperare i valori nel tempo libero.

La scorciatoia evidente, restituendo i valori direttamente all'ascoltatore, funziona, ma si può trovare questa versione più tardi flessibili (e in realtà non molto di più il codice)

1

Naturalmente è possibile utilizzare anche i delegati regolari e APM.

Si noti che lo schema che si descrive è normalmente descritto come Future, un lavoro in background che promette di restituire qualcosa in seguito (un ritorno sull'investimento, se possibile).

Ecco un breve esempio, sotto forma di un programma di console.

uscita:

sequential: 3224 ms 
parallel: 2074 ms 

Naturalmente, dal momento che non sto costruendo le discussioni esplicite, lo lascio al sistema di thread per capire il numero di thread per l'esecuzione in parallelo.

C'è anche disposizioni per essere informato di quando i thread in background sono stati completati, attraverso un metodo di callback, così come il supporto WaitHandle al controllo in modo esplicito e in attesa con timeout, ecc

E la fonte:

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; 
     } 
    } 
} 
Problemi correlati