Entwickler-Ecke

WinForms - BackgroundWorker, CancelAsync funktioniert nicht.


WSS-130 - Fr 25.01.13 14:58
Titel: BackgroundWorker, CancelAsync funktioniert nicht.
Hi,

ich überarbeite gerade mein Programm und möchte den Export im BackgroundWorker ausführen.

Beim klicken des "Export"-Buttons, wird also:

C#-Quelltext
1:
background_Export.RunWorkerAsync(exportFile);                    


Nun sollte wenn ich diese Methode debugge das Programm doch in:


C#-Quelltext
1:
2:
3:
4:
public void background_Export_DoWork(....)
{

}


springen, so dass ich den Code nachvollzeihen kann....
Das macht der Debugger aber nich. :-(


Ralf Jansen - Fr 25.01.13 15:32

Wird sie aufgerufen aber du kannst nicht debuggen oder wird die gar nicht aufgerufen?


WSS-130 - Fr 25.01.13 15:58

Hat sich shcon erledigt. Danke Trotzdem.
Wurde von anfang an aufgerufen, nur wurde zuerst der eine Thread gedebuggt, danach der nächste.

Für Leute mit ähnlichem Problem, komfortable lässt sich das dann mit einem Breakpoint in der DoWork Methode debuggen.

Viele Grüße


WSS-130 - Di 29.01.13 10:43

Das Multithreading über den BackgroundWorker habe ich nich nicht ganz im Griff.

Und zwar wird meine Export Methode wie gewünscht in einem anderen Thread ausgeführt. Dies soll dann über die CancelAsync-methode des BgW abgebrochen werden können. Was nicht möglich ist.
Hier der Teil meines Codes, der den BgW startet und auch wieder abbrechen soll.
GUI:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
private void button_startcancel_Click(object sender, EventArgs e)
{
  //  Zeit messen:
  //watch.Reset();
  //watch.Start();                                  // nur zum Zeitmessen
  //  Zeit messen

  if (background_Export.IsBusy)
  {
    background_Export.WorkerSupportsCancellation = true;
    this.background_Export.CancelAsync();
    button_startcancel.Text = "Start";
  }
  else
  {
    background_Export.RunWorkerAsync(tree_select.SelectedNode);
    button_startcancel.Text = "Cancel";
  }
}

BgW:

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:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
 private void background_Export_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  if (e.Error != null)
    MessageBox.Show("Error: " + e.Error.Message);
  else if (e.Cancelled)
    MessageBox.Show("Export canceled.");
  else
  {
    button_startcancel.Text = "Start";
    //MessageBox.Show("Einlesen beendet in: " + watch.ElapsedMilliseconds + "ms");
  }
}
private void background_Export_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  export.CurrentState state = (export.CurrentState)e.UserState;
}
private void background_Export_DoWork(object sender, DoWorkEventArgs e)
{

  dbMap myDbMap = new dbMap();

  System.ComponentModel.BackgroundWorker worker;
  worker = (System.ComponentModel.BackgroundWorker)sender;
  export exportData = new export();

  TreeNode selected = (TreeNode)e.Argument;

  if (selected == null)
  {
    MessageBox.Show("Bitte Datei auswählen");
  }
  else
  {
    foreach (dataset element in data)
    {
      if (element.callDatasetName == selected.Text)
      {
        foreach (string path in element.callPathMap)
        {
          myDbMap.Import(path);
        }
        myDbFlow.ErzeugenAGK(element.callDatasetName, ref myDbMap);

        if (checkBox_csv.Checked)
          exportData.exportCSV(myDbSignFlow.getContainer, saveFolder + element.callDatasetName + ".csv");
        if (checkBox_xls.Checked)
          exportData.exportXLS(myDbSignFlow.getContainer, saveFolder + element.callDatasetName + ".xlsx");
      }
    }
  }
}


Etwas Erklärung:
Die button_startcancel_Click(...) Methode läuft im Hauptthread. Der Button steuert sowohl den Start des Exports (background_Export.RunWorkerAsync(...)), wie auch das Abbrechen (backgrund_Export.CancelAsync().
Wenn ich ein Export starte und dann auf den Button klicke, is "IsBusy"= true und die CancellationPending wird ebenfalls auf true gesetzt. Der Text des buttons wechselt wieder auf Start.
Die CancelAsync wird aber wohl nicht bis zum Ende ausgeführt und das Programm springt nach dem ausführen der button_startcancel-Click Methode direkt in "background_Export_RunWorkerCompleted(...)". Das Event "Canceled" des Workers ist false.

Und entsprechend wird auch die Datei erzeugt....

Das ist mein erstes Mutlithreading Programm. Bei MSDN habe ich bisher was über Racebedingungen und Deadlocks gelesen. Löse ich eine Racebedingung aus? Oder ist der Grund, dass das Abbrechen nicht funktioniert?

Danke für eure Hilfe!

Grüße


Ralf Jansen - Di 29.01.13 11:00

Folgendes aus der MSDN Doku zu Cancel Async.
Zitat:

CancelAsync fordert das Abbrechen des anstehenden Hintergrundvorgangs an und legt die CancellationPending-Eigenschaft auf true fest.

Über den Aufruf von CancelAsync kann die Worker-Methode ihre Ausführung anhalten und sich selbst beenden.Der Worker-Code sollte regelmäßig prüfen, ob die CancellationPending-Eigenschaft auf true festgelegt wurde.