Entwickler-Ecke
C# - Die Sprache - Auf Abbruch des Backgroundworker warten
snowy1980 - Mi 03.06.09 09:28
Titel: Auf Abbruch des Backgroundworker warten
Hallo,
Ich rufe einen Backgroundworker in einer Schleife zum starten auf und beende ihn später wieder.
(Ausschnitt)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| do {
if (e != null) { if (backWorkUDSmsgVariable.IsBusy == false) { backWorkUDSmsgVariable.RunWorkerAsync(e); } else { lbTestfallInfo.Items.Add("bgw is busy!"); return; } } else { lbTestfallInfo.Items.Add("bgw e != null!"); return; }
...
backWorkUDSmsgVariable.CancelAsync(); } while(...) |
Backgroundworker:
(Ausschnitt)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| ...
if (this.backWorkUDSmsgVariable.CancellationPending==true) { lbTestfallInfo.Items.Add("bgw cancel"); return; }
... |
Der BGW wird nicht beendet, deshalb kommt in der 2.ten Schleife die Meldung das der BGW busy ist.
Wie kann ich ihn richtig beenden, bzw. warten bis er fertig ist..?
Vielen Dank!
Kha - Mi 03.06.09 10:03
Warten kannst du über das RunWorkerCompleted-Event, dazu wirst du deinen Code aber umstrukturieren müssen. Was genau hast du denn vor?
snowy1980 - Mi 03.06.09 11:20
In einer Hauptschleife werden nacheinander mehrere Funktionen ausgeführt. Jede Funktion stellt eine Testroutine für einen Hardwaretestplatz dar. In jeder Funktion werden mittels Backgroundworker über einen Bus zyklische Nachrichten gesendet.
Diese zyklischen Nachrichten sollen starten beim Funktionsaufruf(aktueller Test) und beendet werden wenn dieser Test fertig ist. Die Messages haben jeweils unterschiedliche IDs.
Es kann auch in zweiaufeinanderfolgenden Funktionen sein, das die gleiche Message verschickt wird (also der gleiche Backgroundworker). Dann kommt das Problem das der erste aufruf nicht beendet ist.
Deshalb möchte ich in jder Testfunktion warten bis der worker fertig ist und dann die Routine beenden.
Ich hoffe ich konnte es halbwegs erklären was ich möchte..
[Edit]
Über CancelAsync() forder ich doch den Worker auf abzubrechen. Im Worker wird dies über CancellationPending=true? abgefragt. Warum wird dann dort nicht der Worker beendet?
Im Debugger habe ich erfolgreich die Änderung von false auf true getestet von CancellationPending. Sollte dann nicht gleich das return ausgeführt werden?
In der Funktion RunWorkerCompleted des Workers habe ich eine Ausgabe wann dies geschieht. Diese kommt irgendwann später erst..
Kha - Mi 03.06.09 13:40
snowy1980 hat folgendes geschrieben : |
Sollte dann nicht gleich das return ausgeführt werden? |
Kommt ganz darauf an, ob du die Abfrage oft genug ausführst. Vor allem: Der Zugriff auf die ListBox hat dort doch nichts zu suchen, da wird dir eine Cross-Threading-Exception um die Ohren fliegen.
snowy1980 - Do 04.06.09 09:51
Der Zugriff auf die Listbox ist hier gewollt. Da würde ich an der Exception sehen das er dort reingesprungen ist. Hab das jetzt entfernt.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| do { Thread.Sleep(cycleTime); CanApi2.Write(Globals.hClient, Globals.hNet, ref msg, ref msgTimeStamp);
if (this.backWorkUDSmsgVariable.CancellationPending == true) { return; } } while (true); |
Dies ist die Schleife. Wenn das Cancellation einmal auf true ist bleibt das dann nicht so. Wäre es damit nicht "egal" wie schnell die Schleife durchlaufen wird?
Diesen Backgroundworker hatte ich vorher zum Testen auf dem Form mit einem Button versehen (Start/Stop). Da hatte das auch funktioniert mit dem Abbrechen..
Was muss ich jetzt verändern?
C#-Quelltext
1:
| private void backWorkUDSmsgVariable_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e) |
Diese Funktion empfängt ja das Ereignis über den Abbruch durch EventArgs e.
Jetzt müsste ich ja in meiner Funktion die den BGW verwendet so lange warten bis das Ereignis dort eingetroffen ist oder?
Aber wie?
Kha - Do 04.06.09 12:06
snowy1980 hat folgendes geschrieben : |
Diesen Backgroundworker hatte ich vorher zum Testen auf dem Form mit einem Button versehen (Start/Stop). Da hatte das auch funktioniert mit dem Abbrechen.. |
So langsam wird es merkwürdig ;) :| . Wenn es wirklich mit dem gleichen Code einmal funktioniert und einmal nicht, kann ich dir so nicht weiterhelfen :nixweiss: .
snowy1980 hat folgendes geschrieben : |
Diese Funktion empfängt ja das Ereignis über den Abbruch durch EventArgs e.
Jetzt müsste ich ja in meiner Funktion die den BGW verwendet so lange warten bis das Ereignis dort eingetroffen ist oder?
Aber wie? |
Du könntest natürlich im EventHandler ein boolesches Feld auf true setzen und darauf in der Schleife warten (-> Vollauslastung), sauberer wäre es aber, die Schleife aufzulösen und im RunWorkerCompleted den nächsten Test anzustoßen.
snowy1980 - Do 04.06.09 13:15
Danke erstmal für Deine Hilfe.
Ich habe jetzt in der Completed Funktion des workers einen Funktionaufruf der einfach true zurück gibt.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| private void backWorkUDSmsgVariable_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e) { ReturnBGWcancel(); }
private bool ReturnBGWcancel() { lbTestfallInfo.Items.Add("ReturnBGWcancel=true"); return true; } |
In meiner Tesfallfunktion habe ich zum Schluss eine Schleife die auf ein True wartet um abbzubrechen..
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| bool retBGWcancel = false;
do { retBGWcancel = ReturnBGWcancel(); } while (!retBGWcancel); lbTestfallInfo.Items.Add("Testfall Fertig!"); |
Wenn ich jetzt in meiner Form angeben diesen Testfall zweimal zu durchlaufen, kommt beim ersten Durchlauf:
Ausgabe:
ReturnBGWcancel=true
Testfall Fertig!
Dieser Testdurchlauf ist ok.
Zwischen den Testfällen wird noch eine Init() Funktion gestartet. Diese läuft durch.
Ausgabe:
Init()
Dann kommt der zweite Aufruf, dort kommt bei der Abfrage ob der worker busy ist ein true und es kommt eine Ausgabe:
Ausgabe:
bgw.busy!
Init() //nochmal zum Schluss.
Und am Ende steht jetzt nochmal:
ReturnBGWcancel=true
Den letzten Aufruf verstehe ich nicht..
Kha - Do 04.06.09 14:58
snowy1980 hat folgendes geschrieben : |
Ich habe jetzt in der Completed Funktion des workers einen Funktionaufruf der einfach true zurück gibt. |
Sorry, aber das macht vorne und hinten keinen Sinn :gruebel: . Du gibst zwar ein true zurück, wirfst das Ergebnis aber einfach weg. Und deine Warte-Schleife wird natürlich nur ein einziges mal durchlaufen, ganz unabhängig vom BGW.
Noch einmal: Im Completed-Handler setzt du ein Bool-
Feld (keine lokale Variable) auf true. In der Schleife wartest du darauf, dass dieses true wird, und setzt es danach auf false.
snowy1980 - Do 04.06.09 15:12
Ok hast natürlich Recht damit, das kann nicht funktionieren.
Ich dachte die comleteted Funktion des BGW ist der Completed Handler...
Wo ist der completed Handler damit ich den bool wert setzen kann?
Sorry hab sehr wenig Erfahrung mit C#.
Danke für Deine Hilfe.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!