C #: in attesa di completamento di tutti i thread

Mi sto imbattendo in un modello comune nel codice che sto scrivendo, in cui devo aspettare che tutti i thread di un gruppo vengano completati, con un timeout. Il timeout dovrebbe essere il tempo necessario per il completamento di tutti i thread, quindi è sufficiente eseguire thread.Join (timeout) per ogni thread non funzionerà, poiché il timeout ansible è quindi il timeout * numThreads.

In questo momento faccio qualcosa di simile al seguente:

var threadFinishEvents = new List(); foreach (DataObject data in dataList) { // Create local variables for the thread delegate var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset); threadFinishEvents.Add(threadFinish); var localData = (DataObject) data.Clone(); var thread = new Thread( delegate() { DoThreadStuff(localData); threadFinish.Set(); } ); thread.Start(); } Mutex.WaitAll(threadFinishEvents.ToArray(), timeout); 

Tuttavia, sembra che ci dovrebbe essere un idioma più semplice per questo genere di cose.

Continuo a pensare che usare Join sia più semplice. Registrare il tempo di completamento previsto (come ora + timeout), quindi, in un ciclo, fare

 if(!thread.Join(End-now)) throw new NotFinishedInTime(); 

Con .NET 4.0 trovo che System.Threading.Tasks è molto più semplice da utilizzare. Ecco il ciclo spin-wait che funziona in modo affidabile per me. Blocca il thread principale fino al completamento di tutte le attività. C’è anche Task.WaitAll , ma questo non ha sempre funzionato per me.

  for (int i = 0; i < N; i++) { tasks[i] = Task.Factory.StartNew(() => { DoThreadStuff(localData); }); } while (tasks.Any(t => !t.IsCompleted)) { } //spin wait 

Dal momento che la domanda è stata interrotta, andrò avanti e pubblicherò la mia soluzione.

 using (var finished = new CountdownEvent(1)) { for (DataObject data in dataList) { finished.AddCount(); var localData = (DataObject)data.Clone(); var thread = new Thread( delegate() { try { DoThreadStuff(localData); threadFinish.Set(); } finally { finished.Signal(); } } ); thread.Start(); } finished.Signal(); finished.Wait(YOUR_TIMEOUT); } 

In cima alla mia testa, perché non basta Thread.Join (timeout) e rimuovi il tempo impiegato per partecipare al timeout totale?

 // pseudo-c#: TimeSpan timeout = timeoutPerThread * threads.Count(); foreach (Thread thread in threads) { DateTime start = DateTime.Now; if (!thread.Join(timeout)) throw new TimeoutException(); timeout -= (DateTime.Now - start); } 

Modifica: il codice ora è meno pseudo. non capisco perché modificherai una risposta -2 quando la risposta che hai modificato +4 è esattamente la stessa, solo meno dettagliata.

Questo non risponde alla domanda (nessun timeout), ma ho fatto un metodo di estensione molto semplice per attendere tutti i thread di una raccolta:

 using System.Collections.Generic; using System.Threading; namespace Extensions { public static class ThreadExtension { public static void WaitAll(this IEnumerable threads) { if(threads!=null) { foreach(Thread thread in threads) { thread.Join(); } } } } } 

Quindi chiami semplicemente:

 List threads=new List(); //Add your threads to this collection threads.WaitAll(); 

Questo potrebbe non essere un’opzione per te, ma se puoi usare Parallel Extension per .NET puoi utilizzare Task s invece di thread non Task.WaitAll() e quindi utilizzare Task.WaitAll() per attendere il loro completamento.

Stavo legando per capire come fare questo ma non potrei ottenere alcune risposte da google. So che questo è un vecchio thread ma qui c’era la mia soluzione:

Usa la seguente class:

 class ThreadWaiter { private int _numThreads = 0; private int _spinTime; public ThreadWaiter(int SpinTime) { this._spinTime = SpinTime; } public void AddThreads(int numThreads) { _numThreads += numThreads; } public void RemoveThread() { if (_numThreads > 0) { _numThreads--; } } public void Wait() { while (_numThreads != 0) { System.Threading.Thread.Sleep(_spinTime); } } } 
  1. Chiama Addthreads (int numThreads) prima di eseguire un thread (s).
  2. Chiama RemoveThread () dopo che ognuno ha completato.
  3. Utilizzare Wait () nel punto in cui si desidera attendere il completamento di tutti i thread prima di continuare

Ho letto il libro C # 4.0: Il riferimento completo di Herbert Schildt. L’autore usa join per dare una soluzione:

 class MyThread { public int Count; public Thread Thrd; public MyThread(string name) { Count = 0; Thrd = new Thread(this.Run); Thrd.Name = name; Thrd.Start(); } // Entry point of thread. void Run() { Console.WriteLine(Thrd.Name + " starting."); do { Thread.Sleep(500); Console.WriteLine("In " + Thrd.Name + ", Count is " + Count); Count++; } while (Count < 10); Console.WriteLine(Thrd.Name + " terminating."); } } // Use Join() to wait for threads to end. class JoinThreads { static void Main() { Console.WriteLine("Main thread starting."); // Construct three threads. MyThread mt1 = new MyThread("Child #1"); MyThread mt2 = new MyThread("Child #2"); MyThread mt3 = new MyThread("Child #3"); mt1.Thrd.Join(); Console.WriteLine("Child #1 joined."); mt2.Thrd.Join(); Console.WriteLine("Child #2 joined."); mt3.Thrd.Join(); Console.WriteLine("Child #3 joined."); Console.WriteLine("Main thread ending."); Console.ReadKey(); } } 

Possibile soluzione:

 var tasks = dataList .Select(data => Task.Factory.StartNew(arg => DoThreadStuff(data), TaskContinuationOptions.LongRunning | TaskContinuationOptions.PreferFairness)) .ToArray(); var timeout = TimeSpan.FromMinutes(1); Task.WaitAll(tasks, timeout); 

Supponendo dataList è l’elenco degli articoli e ogni articolo deve essere elaborato in un thread separato.