2010-10-13 13 views
5

come fare in modo che il thread in primo piano attenda che tutti i thread in background (figlio) finiscano in C#? Devo ottenere l'elenco dei lavori in sospeso dalla coda (database), avviare un nuovo thread per eseguirli e infine attendere che tutti i thread figli finiscano. come farlo in C#? Grazie in anticipo.come aspettare che tutti i thread in background finiscano (in C#)?

+2

possibile duplicato del [C# Spawn Fili multipli per lavora quindi aspetta fino a quando tutto è finito] (http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished) –

+0

grazie per tutte le risposte rapide a la mia domanda – RKP

+0

hai provato [EventWaitHandle();] (http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx) – Bonshington

risposta

1

Considerare l'utilizzo ThreadPool. La maggior parte di ciò che vuoi è già fatto. C'è un example from Microsoft che fa praticamente tutto il tuo compito. Sostituisci "fibonacci" con "compito del database" e suona come il tuo problema.

+0

Ho letto questo articolo pochi minuti fa e stavo per rispondere dicendo che è la soluzione che stavo cercando. Grazie per la risposta. – RKP

7

È possibile memorizzare ogni thread avviato in una matrice. Quindi, quando è necessario attendere tutti, chiama il metodo Join su ciascun thread in una matrice in un ciclo.

Thread child = new Thread(...); 
Threads.Add(child); 
child.Start() 

... 

foreach(Thread t in Threads) 
{ 
    t.Join(); 
} 

HTH

+0

Grazie per la risposta. Penso che il metodo thread.Join è buono per un singolo thread o pochissimi il numero fisso di thread. per più thread, penso che ci sia un metodo WaitAll, ma non sono riuscito a trovare un buon esempio di codice per questo. – RKP

+3

@RKP: aspettare che tutti i thread finiscano è come aspettare a loro volta, vero? C'è una funzione winapi WaitForMultipleObjects, ma non è C#, sebbene tu possa usarla, ma non vedo alcun punto. –

1

Questo è il codice incompleta, ma ManualResetEvent lavori per voi

var waitEvents = new List<ManualResetEvent>(); 
foreach (var action in actions) 
{ 
    var evt = new ManualResetEvent(false); 
    waitEvents.Add(evt); 
    ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, TimeoutCallback, state, 5000, true); 
} 

if (waitEvents.Count > 0) 
    WaitHandle.WaitAll(waitEvents.ToArray()); 
+0

Grazie, ma dove il nuovo thread per ogni azione viene avviato qui in questo codice? è "5000" un'impostazione di timeout? – RKP

+0

Cerca qui l'intero codice, ho appena copiato un po 'da una delle mie risposte precedenti: http://stackoverflow.com/questions/3915017/image-url-validation-in-c/3915440#3915440 – danijels

+0

E sì, 5000 è stato un timeout – danijels

0

Creare una struttura per tenere traccia dei tuoi thread di lavoro

private struct WorkerThreadElement 
{ 
    public IAsyncResult WorkerThreadResult; 
    public AsyncActionExecution WorkerThread; 
} 

È inoltre necessario tenere traccia del numero totale di thread che si prevede di creare e il numero di thread che hanno attualmente completato

private int _TotalThreads = 0; 
private int _ThreadsHandled = 0; 
private List<WorkerThreadElement> _WorkerThreadElements = new List<WorkerThreadElement>(); 

Quindi creare un handle autoreset per attendere il completamento del thread.

// The wait handle thread construct to signal the completion of this process 
private EventWaitHandle _CompletedHandle = new AutoResetEvent(false); 

È inoltre necessario un delegato per creare nuove discussioni - Ci sono diversi modi di fare questo, ma ho scelto un semplice delegato per il bene di questo esempio

// Delegate to asynchronously invoke an action 
private delegate void AsyncActionExecution(); 

Consente asume che il metodo Invoke è il punto di ingresso che creerà tutti i thread e attenderà la loro esecuzione. Quindi:

public void Invoke() 
{ 
    _TotalThreads = N; /* Change with the total number of threads expected */ 

    foreach (Object o in objects) 
    { 
     this.InvokeOneThread(); 
    }    

    // Wait until execution has been completed 
    _CompletedHandle.WaitOne(); 

    // Collect any exceptions thrown and bubble them up 
    foreach (WorkerThreadElement workerThreadElement in _WorkerThreadElements) 
    { 
     workerThreadElement.WorkerThread.EndInvoke(workerThreadElement.WorkerThreadResult); 
    } 
}   

InvokeOneThread è il metodo utilizzato per creare un singolo thread per un'operazione. Qui abbiamo bisogno di creare un elemento thread di lavoro e richiamare il thread attuale.

private void InvokeOneThread() 
{ 
    WorkerThreadElement threadElement = new WorkerThreadElement(); 
    threadElement.WorkerThread = new AsyncActionExecution(); 
    threadElement.WorkerThreadResult = threadElement.WorkerThread.BeginInvoke(actionParameters, InvokationCompleted, null); 

    _WorkerThreadElements.Add(threadElement); 
} 

richiamata dal completamento filo

private object _RowLocker = new object(); 

/// <summary> 
/// Increment the number of rows that have been fully processed 
/// </summary> 
/// <param name="ar"></param> 
private void InvokationCompleted(IAsyncResult ar) 
{ 
    lock (_RowLocker) 
    { 
     _RowsHandled++; 
    } 

    if (_TotalThreads == _ThreadsHandled) 
     _CompletedHandle.Set(); 
} 

Fatto

1

Utilizzando i dati dinamici è possibile passare l'oggetto e il WaitHandle (ActionResetEvent) che consente di attendere per tutti i thread in background per terminare senza dichiarare una classe in più:

static void Main(string[] args) 
{ 
    List<AutoResetEvent> areList = new List<AutoResetEvent>(); 
    foreach (MyObject o in ListOfMyObjects) 
    { 
     AutoResetEvent are = new AutoResetEvent(false); 
     areList.Add(are); 
     ThreadPool.QueueUserWorkItem(DoWork, new { o, are }); 
    }; 

    Console.WriteLine("Time: {0}", DateTime.Now); 
    WaitHandle.WaitAll(areList.ToArray()); 
    Console.WriteLine("Time: {0}", DateTime.Now); 
    Console.ReadKey(); 
} 

static void DoWork(object state) 
{ 
    dynamic o = state; 
    MyObject myObject = (MyObject)o.o; 
    AutoResetEvent are = (AutoResetEvent)o.are; 

    myObject.Execute(); 
    are.Set(); 
} 
Problemi correlati