2010-10-13 17 views
5

wie der Vordergrund-Thread auf alle Hintergrund (untergeordneten) Threads warten in C# zu beenden? Ich muss eine Liste der ausstehenden Jobs aus der Warteschlange (Datenbank) abrufen, einen neuen Thread starten, um sie auszuführen, und schließlich auf alle untergeordneten Threads warten. wie geht das in C#? Danke im Voraus.Wie warten Sie, bis alle Hintergrundthreads fertig sind (in C#)?

+2

möglich Duplikat [C# Spawn mehrere Threads für arbeite dann warte bis alles fertig ist] (http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished) –

+0

danke für alle schnellen Antworten auf Meine Frage – RKP

+0

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

Antwort

1

Betrachten Threadpool verwenden. Das meiste von dem, was Sie wollen, ist bereits erledigt. Es gibt eine example from Microsoft, die so ziemlich deine gesamte Aufgabe erledigt. Ersetzen Sie "fibonacci" durch "database task" und es klingt wie Ihr Problem.

+0

Ich las diesen Artikel ein paar Minuten zurück und war im Begriff zu sagen, das ist die Lösung, die ich suchte. danke für die Antwort. – RKP

7

Sie könnten jeden gestarteten Thread in einem Array speichern. Wenn Sie dann auf alle warten müssen, rufen Sie die Join-Methode für jeden Thread in einem Array in einer Schleife auf.

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

... 

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

HTH

+0

Danke für die Antwort. Ich denke thread.Join Methode ist gut für einen einzelnen Thread oder sehr wenige feste Anzahl von Threads. Für mehrere Threads denke ich, dass es eine WaitAll-Methode gibt, aber ich konnte kein gutes Codebeispiel dafür finden. – RKP

+3

@RKP: Warten auf alle Threads zu beenden ist das gleiche wie auf sie zu warten, nicht wahr? Es gibt eine winapi-Funktion WaitForMultipleObjects, aber es ist nicht C#, obwohl Sie es verwenden können, aber ich sehe keinen Sinn. –

1

Dies ist unvollständig Code, aber ManualResetEvent Arbeiten für Sie

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

Danke, aber wo wird der neue Thread für jede Aktion hier in diesem Code gestartet? ist "5000" eine Zeitüberschreitung? – RKP

+0

Schauen Sie hier für den gesamten Code, ich habe nur ein bisschen von einer meiner früheren Antworten kopiert: http://StackOverflow.com/Questions/3915017/image-URL-validation-in-C/3915440#3915440 – danijels

+0

Und ja, 5000 war eine Timeout-Einstellung – danijels

0

eine Struktur erstellen Überblick über Ihre Arbeitsthreads zu halten

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

Sie müssen auch Verfolgen Sie die Gesamtzahl der zu erstellenden Threads und die Anzahl der aktuell vorhandenen Threads abgeschlossen

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

Erstellen Sie dann ein Autoreset-Handle, um auf die Beendigung des Threads zu warten.

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

Sie auch einen Delegaten brauchen neue Themen zu erstellen - Es gibt mehrere Möglichkeiten, dies zu tun, aber ich habe einen einfachen Delegierten zum Zwecke dieses Beispiels

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

Lets asume dass die Invoke-Methode gewählt ist der Eingangspunkt, der alle Threads erstellt und auf deren Ausführung wartet. So haben wir:

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 ist die Methode, um einen einzelnen Thread für eine Operation zu erstellen. Hier müssen wir ein Worker-Thread-Element erstellen und den aktuellen Thread aufrufen.

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

    _WorkerThreadElements.Add(threadElement); 
} 

Rückruf von Gewinden Abschluss

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

Fertig
1

Verwendung dynamischer Daten, die Sie Ihr Objekt und das Waithandle (ActionResetEvent) passieren kann, dass Sie für alle Hintergrund-Threads ohne erklärt eine zusätzliche Klasse zu beenden warten lässt:

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