Wie man BackgroundWorker ProgressChanged-Ereignisse führen in der Folge?
Betrachten Sie den folgenden code:
private static BackgroundWorker bg = new BackgroundWorker();
static void Main(string[] args) {
bg.DoWork += bg_DoWork;
bg.ProgressChanged += bg_ProgressChanged;
bg.WorkerReportsProgress = true;
bg.RunWorkerAsync();
Thread.Sleep(10000);
}
static void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
Console.WriteLine(e.ProgressPercentage);
Thread.Sleep(100);
Console.WriteLine(e.ProgressPercentage);
}
static void bg_DoWork(object sender, DoWorkEventArgs e) {
for (int i = 0; i < 10; i++) {
bg.ReportProgress(i);
}
}
Beim ausführen bekomme ich folgende Ausgabe:
0
1
1
2
0
3
2
3
5
4
4
6
5
7
7
8
6
9
8
9
Verstehe ich, dass das Problem einer race-Bedingung zwischen den threads, BackgroundWorker startet für jeden Aufruf von ReportProgress.
Wie kann ich sicher stellen, dass der ganze Körper von jedem bg_ProgressChanged wird ausgeführt, in der Reihenfolge in der ich Sie berufen habe?
Das ist, hätte ich gerne
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
als Ergebnis.
BackgroundWorker ist nicht wirklich gemeint zu sein, ohne UI-thread.
Bevorzugen Tritt parameter von ReportProgress in den Schritten und nicht das userState-parameter an. Schlagen Sie zu, schauen Sie bitte auf in diesem MSDN-link für die Berichterstattung über die Fortschritte: msdn.microsoft.com/en-us/library/a3zbdb1t.aspx
Danke. Fixiert es.
Versuchen Sie, wickeln Sie die ReportProgress-Methode aufrufen, in eine Sperre(_objectLock) block z.B. lock(_lockObject) { bg.ReportProgress(i); }
Das wird nicht keinen Unterschied machen, überhaupt, solche Anrufe auf dem gleichen thread ausgeführt.
Bevorzugen Tritt parameter von ReportProgress in den Schritten und nicht das userState-parameter an. Schlagen Sie zu, schauen Sie bitte auf in diesem MSDN-link für die Berichterstattung über die Fortschritte: msdn.microsoft.com/en-us/library/a3zbdb1t.aspx
Danke. Fixiert es.
Versuchen Sie, wickeln Sie die ReportProgress-Methode aufrufen, in eine Sperre(_objectLock) block z.B. lock(_lockObject) { bg.ReportProgress(i); }
Das wird nicht keinen Unterschied machen, überhaupt, solche Anrufe auf dem gleichen thread ausgeführt.
InformationsquelleAutor Andris | 2011-11-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
BackgroundWorker
wirftProgressChanged
Ereignisse auf, wird der aktuelle SynchronizationContext aus dem thread, der genanntRunWorkerAsync()
.Dem Synchronisierungskontext läuft Rückrufe auf dem ThreadPool-ohne Synchronisierung.
Wenn Sie mit der BackgroundWorker-Klasse in einer UI-Anwendung (WPF oder WinForms) zu verwenden, wird die Benutzeroberfläche der Plattform SynchronizationContext, der ausgeführt wird, Rückrufe in Ordnung.
Mein Problem ist, dass ich möchte, dass der ganze Körper des ProgressChanged-Ereignis ausführen, in der Reihenfolge in der ich Sie berufen habe. Ich update die Frage zu reflektieren, besser, was ich gerne tun würde.
Unter einer Benutzeroberfläche SynchronizationContext, die Sie ausführen, in Ordnung.
Wie gesagt habe ich geändert, die Anwendung, die Art der Ausgabe an eine Windows-Anwendung, aber bitte nicht in der Ausgabe, die in meinem überarbeiteten Beispiel die ersten 5 kommt, bevor die ersten 4, also der Aufruf mit dem parameter 5 wurde durchgeführt, bevor die mit parameter 4. Ändert sich nicht die Art der Ausgabe genug? Ich bin mir nicht sicher, wie die SynchronizationContext-zu einem "UI SynchronizationContext".Ich bin nicht vertraut mit dem Thema.
Sie ausführen müssen, um einen UI-thread durch den Aufruf
Application.Run()
. (dies ist ein blockierender Aufruf). Art des Projektes spielt überhaupt keine Rolle. Allerdings, wenn Sie es nicht tun, UI, Sie wahrscheinlich sollte nicht sein mit einem BackgroundWorker überhaupt.InformationsquelleAutor SLaks
Verwenden Sie nicht diese Lösung!!!!! Kann zu einem Deadlock führen, wie SLaks hat darauf hingewiesen.
Scheine ich stolperte über eine Antwort. Ich änderte den code auf folgende Weise:
und jetzt bekomme ich die Ausgabe, die ich will:
Beachten Sie, dass dies kann zu deadlocks führen.
[MethodImpl(MethodImplOptions.Synchronized)]
entsprichtlock(this)
und sollte nicht verwendet werden.Guter Tipp. Nochmals vielen Dank.
InformationsquelleAutor Andris