Autor Beitrag
snowy1980
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Mi 03.06.09 09:28 
Hallo,

Ich rufe einen Backgroundworker in einer Schleife zum starten auf und beende ihn später wieder.

(Ausschnitt)
ausblenden 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
{

//Starten
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(); //Beenden

}
while(...)


Backgroundworker:

(Ausschnitt)
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
...

// Check for cancelation
                        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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 03.06.09 13:40 
user profile iconsnowy1980 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: 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.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
do
                    {
                        Thread.Sleep(cycleTime);   //1000ms
                        
                        //msg senden
                        CanApi2.Write(Globals.hClient, Globals.hNet, ref msg, ref msgTimeStamp);

                        // Check for cancelation
                        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?

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 04.06.09 12:06 
user profile iconsnowy1980 hat folgendes geschrieben Zum zitierten Posting springen:
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: .

user profile iconsnowy1980 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: 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.

ausblenden 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..

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 04.06.09 14:58 
user profile iconsnowy1980 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: 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.
snowy1980 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Do 04.06.09 16:15 
Die Lösung habe ich hier gefunden:

newsgroups.seducy.de...2/Archiv/archiv.html

Damit kann auf das beenden einen Backgroundworkers gewartet werden (DoEvents() aufrufen).

Danke trotzdem für Deine Hilfe!!