Wie kann ich bis zum Abschluss von BackgroundWorker warten?

Beachten Sie die folgende Stück code:

var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnAsyncOperationCompleted;
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);

Nehmen wir nun an will ich warten, bis bw Oberflächen arbeiten. Was ist der richtige Weg, dies zu tun?

Meine Lösung ist diese:

bool finished = false;
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += (sender, args) =>
{
  OnAsyncOperationCompleted(sender, args);
  finished = true;
});
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
int timeout = N;
while (!finished && timeout > 0)
{
  Thread.Sleep(1000);
  --timeout;
}
if (!finished)
{
  throw new TimedoutException("bla bla bla");
}

Aber ich mag es nicht.

Ich habe als Ersatz die finished Flagge mit einem Synchronisations-event, setzen Sie ihn in die RunWorkerCompleted hf block auf später, statt der while-Schlaf-Schleife.

Ach, es ist falsch, denn der code kann ausgeführt werden in der WPF oder WindowsForm Synchronisation Zusammenhang, in dem Fall würde ich block den gleichen thread wie die RunWorkerCompleted handler wird ausgeführt, und das ist eindeutig nicht sehr smart move.

Ich würde gerne wissen, die bessere Lösung.

Dank.

EDIT:

P. S.

  • Der Beispielcode ist so künstlich, absichtlich zu klären, meine Frage. Ich bin mir durchaus bewusst das Abschluss-Rückruf und doch möchte ich wissen, wie zu warten bis zur Fertigstellung. Das ist meine Frage.
  • Ich bin mir bewusst Thread.Join, Delegate.BeginInvoke, ThreadPool.QueueUserWorkItem usw... Die Frage ist speziell über BackgroundWorker.

EDIT 2:

OK, ich denke, es wird viel einfacher, wenn ich erkläre, das Szenario.

Habe ich ein unit-test-Methode, die ruft einige asynchrone code, die wiederum letztlich greift ein BackgroundWorker zu denen auch ich bin in der Lage, einen pass completion handler. Der gesamte code ist von mir, so dass ich ändern kann, die Umsetzung, wenn ich möchte.
Ich bin nicht, jedoch, ersetzen Sie die BackgroundWorker, weil es verwendet automatisch die richtige Synchronisierung-Kontext, so dass, wenn der code aufgerufen wird, auf einen UI-thread der Fertigstellung callback wird aufgerufen, auf dem selben UI-thread, der ist sehr gut.

Jedenfalls ist es möglich, dass der unit-test-Methode trifft das Ende vor den BW seine Arbeit beendet hat, das ist nicht gut. Deshalb möchte ich warten, bis die BW abgeschlossen und würde gerne wissen, der beste Weg für Sie.

Gibt es mehr Teile, aber das Gesamtbild ist mehr oder weniger wie ich es gerade beschrieben habe.

Kommentar zu dem Problem
Ich glaube, ein hintergrund-worker kann mehrere aktive threads, was willst du noch warten? Und was passiert, wenn Ihr warten code wird aufgerufen, wenn ein anderes hintergrund-Arbeiter gerade geplant? Ich glaube, das ist der Grund dieser Frage hält reparieren. Kommentarautor: CodingBarfield
@Barfieldmv: Das ist, warum die AutoResetEvent ist so eine elegante Lösung. Sie können warten, für eine Aufgabe oder mehrere, egal was für einen thread, in dem Sie gerade laufen. Für mehrere Aufgaben benutzen Sie einfach die statische Methode AutoResetEvent.WaitAll(new[] {doneEvent1, doneEvent2}) Kommentarautor: JohannesH
@JohannesH in der Lage sein, zu warten auf mehrere Ereignisse, die Sie haben, um sicherzustellen, dass Sie Feuer und behandelt erhalten. Ich befürchte, dass die Sperrung auf einen UI-thread zum Beispiel blockiert alle Ereignisse auf einem windows-Formular, so dass Sie ewig warten. Wenn ich mich richtig erinnere eine backgroundworker-Prozesse seinen Dowork-Ereignis auf einem hintergrund-thread und feuert die WorkCompleted-event auf der main-thread, wenn der main-thread nicht blockiert. Dieser betritt das Reich der schwer zu Debuggen, multiple threading-zumindest für mich. Kommentarautor: CodingBarfield
@Barfieldmv: Du hast Recht, das ist nicht so einfach, wie ich dachte, es war. Jedoch, in meinem Beispiel nenne ich doneEvent.Set() aus dem DoWork-Ereignishandler... Also zumindest das ist legitm thread klug. Jedoch, die WaitAll-Aufruf wird nicht funktionieren, da WinForms-und WPF-UI-thread läuft im STA-Modus, so dass ich mich zurückziehe, meine Vorherige Aussage in diesem Zusammenhang. Stattdessen könnte man nennen, WaitAny für N-mal, wobei N die Anzahl der wait-handles. Aber meine Lösung hat immer noch das problem, dass es nicht, und kann nicht warten, für das RunWorkerCompleted-Ereignis-Handler zu beenden, da Sie auch blockiert durch den Aufruf von WaitAny oder WaitOne. Kommentarautor: JohannesH
Ich muss darauf hinweisen, dass das problem mit der RunWorkerCompleted-Ereignishandler blockiert wird, ist auch ein problem in Mark ' s original while(!fertig...){...} Lösung. So, die Lösung wird immer werfen die TimedoutException. Soweit ich sagen kann, es wird nur möglich sein, zu warten, bis die DoWork-Ereignishandler zu beenden, nicht das RunWorkerCompleted-Ereignishandler durch die Natur der BackgroundWorker-Klasse. Auch ist es unmöglich zu garantieren, dass Sie einen job begonnen haben, aber Sie dieses problem lösen könnte, mit einem timeout-Wert. Kommentarautor: JohannesH

InformationsquelleAutor der Frage mark | 2009-08-26

Schreibe einen Kommentar