Threads beenden mit Thread.Abort

Mitten im Umzugs- und Renovierungs-Stress nach langer Zeit nun wieder mal ein Artikel aus dem .NET-Bereich. Über das Thema bin ich heute bei der Arbeit gestolpert.

Hintergrund: Ich bastle gerade eine Multithreading-Anwendung, eigentlich eher eine Dualthread-Anwendung: Ein Thread für die eigentliche Arbeit, einer für die Benutzeroberfläche inklusive “Abbrechen”-Schaltfläche :-) Die Idee ist altbekannt: Der Workerthread läuft im Hintergrund und soll seine Arbeit abbrechen, wenn der User in der Oberfläche auf den entsprechenden Button klickt. Da die Teilergebnisse seiner Arbeit in meinem Fall bei einem Abbruch uninteressant sind kann der Thread also tatsächlich sofort aufhören zu arbeiten, wenn der User das will.
Die simpelste Möglichkeit, ohne irgendwelche Flags als synchronisierte Membervariablen o.ä. zu implementieren, ist ein Aufruf von Thread.Abort. Der Aufruf führt dazu, dass – sowohl im aufrufenden als auch im Workerthread – eine ThreadAbortException geworfen und der Thread (in der Regel) unverzüglich termniniert wird.

Die ThreadAbortException kann allerdings etwas lästig werden, sie ist nämlich nicht tot zu kriegen. Wie die MSDN dazu ausführt:

"ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. "

.

Das kann zur Folge haben, dass die ThreadAbortException an mehreren Stellen in diversen Exception-Handlern hängen bleibt, und der Anwender z.B. in einer MessageBox darüber benachrichtigt wird. Folglich sind diverse Sonderbehandlungen notwendig.

Allerdings ergibt sich hier eine interessante Möglichkeit: Man kann die ThreadAbortException auch dazu benutzen, den WorkerThread davon zu benachrichtigen, dass er sich beenden soll. Möglich wird das, weil die Exception ja auch in ihm (also in seinem Thread) geworfen wird – und dort auch gefangen werden kann. So kann z.B. eine aufgerufene Methode sauber null zurückliefern. Wenn da nicht dass Problem wäre, dass die Exception immer erneut geworfen wird.

Abhilfe schafft hier die Methode Thread.ResetAbort . Diese bricht einen Abort-Request für einen Thread wieder ab, so dass dieser im Prinzip völlig desinteressiert weiterlaufen könnte – oder sich aber auch selbst beenden. In beiden Fällen verschwindet auch die ThreadAbortException wieder. Somit ließe sich ein "sauberer" Abbruch des WorkerThreads nach folgendem Muster realisieren:


class MainForm
{
  protected void btnCancelWorkerThread_Click(object sender, EventArgs e)
  {
    m_workerThread.Abort;
  }
}

class HeavyWorker
{
  public byte[] DoHeavyWork(string params)
  {
    try
    {
      return InternalHeavyWork(params);
    }
    catch (ThreadAbortExcpetion)
    {
      Thread.ResetAbort();
      return null;
    }
  }
}

1 Kommentar

Hinterlasse eine Antwort

Pflichtfelder sind mit * markiert.

*


*