Multithreadanwendungen (C# und Visual Basic)

Sie können in Visual Basic und C# Anwendungen schreiben, die mehrere Aufgaben gleichzeitig ausführen. Tasks, die möglicherweise andere Tasks aufhalten, können in separaten Threads ausgeführt werden. Dieser Prozess wird als Multithreading oder freies Threading bezeichnet.

Anwendungen, die mit Multithreading arbeiten, reagieren schneller auf Eingaben des Benutzers, da ihre Benutzeroberfläche aktiv bleibt, während rechenintensive Tasks in eigenen Threads ausgeführt werden. Multithreading ist außerdem beim Erstellen von skalierbaren Anwendungen hilfreich, da mit wachsender Arbeitsauslastung Threads hinzugefügt werden können.

Tipp

Visual Studio 2010 und .NET Framework 4 verbessern die Unterstützung für parallele Programmierung, indem sie eine neue Laufzeit, neue Klassenbibliothekstypen und neue Diagnosetools bereitstellen. Weitere Informationen finden Sie unter Parallele Programmierung in .NET Framework.

Verwenden der BackgroundWorker-Komponente

Das zuverlässigste Verfahren zum Erstellen einer Multithreadanwendung ist die Verwendung der BackgroundWorker-Komponente. Diese Klasse verwaltet einen eigenen Thread, der speziell für die Verarbeitung der von Ihnen angegebenen Methode vorgesehen ist. Ein Beispiel finden Sie unter Exemplarische Vorgehensweise: Multithreading mit der BackgroundWorker-Komponente (C# und Visual Basic).

Um eine Operation im Hintergrund zu starten, erstellen Sie einen BackgroundWorker, und überwachen Sie Ereignisse, die den Status der Operation melden und ihren Abschluss signalisieren. Sie können das BackgroundWorker-Objekt programmgesteuert erstellen oder es in der Toolbox aus der Registerkarte Komponenten auf ein Formular ziehen. Wenn Sie den BackgroundWorker im Formular-Designer erstellen, wird er auf der Komponentenleiste angezeigt, und seine Eigenschaften werden im Eigenschaftenfenster angezeigt.

Einrichten einer Hintergrundoperation

Um eine Hintergrundoperation einzurichten, fügen Sie einen Ereignishandler für das DoWork-Ereignis hinzu. Rufen Sie die zeitaufwendige Operation in diesem Ereignishandler auf.

Um die Operation zu starten, rufen Sie RunWorkerAsync auf. Um Benachrichtigungen über Statusaktualisierungen zu empfangen, behandeln Sie das ProgressChanged-Ereignis. Um eine Benachrichtigung zu empfangen, wenn die Operation abgeschlossen ist, behandeln Sie das RunWorkerCompleted-Ereignis.

Die Methoden, die das ProgressChanged-Ereignis und das RunWorkerCompleted-Ereignis behandeln, können auf die Benutzeroberfläche der Anwendung zugreifen, da diese Ereignisse in dem Thread ausgelöst werden, der die RunWorkerAsync-Methode aufgerufen hat. Der DoWork-Ereignishandler kann jedoch nicht mit Benutzeroberflächenobjekten arbeiten, da er im Hintergrundthread ausgeführt wird.

Erstellen und Verwenden von Threads

Wenn Sie das Verhalten des Threads der Anwendung genauer steuern müssen, können Sie die Threads selbst verwalten. Sie sollten sich jedoch bewusst sein, dass das Schreiben korrekter Anwendungen mit Multithreading schwierig sein kann: Anwendungen werden möglicherweise nicht mehr reagieren, oder es können durch Racebedingungen vorübergehende Fehler auftreten. Weitere Informationen finden Sie unter Threadsichere Komponenten.

Sie erstellen einen neuen Thread, indem Sie eine Variable vom Typ Thread deklarieren und den Konstruktor mit dem Namen der Prozedur oder der Methode aufrufen, die für den neuen Thread ausgeführt werden soll. Der folgende Code veranschaulicht dies.

Dim newThread As New System.Threading.Thread(AddressOf AMethod)
System.Threading.Thread newThread =
    new System.Threading.Thread(AMethod);

Starten und Beenden von Threads

Verwenden Sie die Start-Methode wie im folgenden Codebeispiel dargestellt, um die Ausführung eines neuen Threads zu starten.

newThread.Start()
newThread.Start();

Verwenden Sie die Abort-Methode wie im folgenden Codebeispiel dargestellt, um die Ausführung eines Threads zu beenden.

newThread.Abort()
newThread.Abort();

Sie können Threads nicht nur starten und beenden, sondern auch anhalten, indem Sie die Sleep-Methode oder die Suspend-Methode aufrufen. Angehaltene Threads können mit der Resume-Methode fortgesetzt werden. Außerdem können Sie einen Thread mit der Abort-Methode zerstören.

Threadmethoden

In der folgenden Tabelle werden einige der Methoden dargestellt, mit denen einzelne Threads gesteuert werden können.

Methode

Aktion

Start

Startet die Ausführung eines Threads.

Sleep

Hält einen Thread für die angegebene Zeit an.

Suspend

Hält einen Thread an, wenn dieser einen sicheren Punkt erreicht.

Abort

Stoppt einen Thread, wenn dieser einen sicheren Punkt erreicht.

Resume

Setzt einen angehaltenen Thread fort.

Join

Veranlasst den aktuellen Thread, die Beendigung eines anderen Threads abzuwarten. Wenn diese Methode mit einem Timeoutwert verwendet wird, gibt sie True zurück, sofern der Thread in der zugewiesenen Zeit beendet wird.

Sichere Punkte

Die meisten dieser Methoden sind selbsterklärend, doch der Begriff sicherer Punkt ist vielleicht neu für Sie. Sichere Punkte werden im Code an Stellen platziert, an denen die Common Language Runtime eine automatische Garbage Collection (Freigabe von nicht verwendeten Variablen und nicht verwendetem Speicherplatz) sicher durchführen kann. Wenn Sie die Methoden Abort oder Suspend eines Threads aufrufen, analysiert die Common Language Runtime den Code und ermittelt eine geeignete Stelle, an der die Ausführung des Threads angehalten werden kann.

Threadeigenschaften

Threads enthalten außerdem einige nützliche Eigenschaften, wie in der folgenden Tabelle dargestellt:

Eigenschaft

Wert

IsAlive

Enthält den Wert True, wenn ein Thread aktiv ist.

IsBackground

Ruft einen Boolean-Wert ab, der angibt, ob ein Thread ein Hintergrundthread ist oder sein sollte, oder legt einen solchen Boolean-Wert fest. Hintergrundthreads gleichen den Vordergrundthreads, verhindern jedoch nicht die Beendigung eines Prozesses. Sobald alle zu einem Prozess gehörenden Vordergrundthreads beendet wurden, beendet die Common Language Runtime den Prozess, indem sie die Abort-Methode für noch aktive Hintergrundthreads aufruft.

Name

Ruft den Namen eines Threads ab oder legt ihn fest. Wird meist zum Erkennen einzelner Threads beim Debuggen verwendet.

Priority

Ruft einen Wert ab oder legt einen Wert fest, anhand dessen das Betriebssystem bei der Threadplanung Prioritäten vergibt.

ApartmentState

Ruft das für einen bestimmten Thread verwendete Threadingmodell ab oder legt es fest. Threadingmodelle sind wichtig, wenn ein Thread nicht verwalteten Code aufruft.

ThreadState

Enthält einen Wert, der den Status oder die Statuswerte eines Threads beschreibt.

Threadprioritäten

Jeder Thread verfügt über eine Prioritäten-Eigenschaft, die die Prozessorzeit festlegt, die dem Thread für die Ausführung eingeräumt wird. Das Betriebssystem ordnet Threads mit hoher Priorität größere Zeiträume und Threads mit niedriger Priorität kürzere Zeiträume zu. Neue Threads werden mit dem Wert Normal erstellt, doch Sie können die Priority-Eigenschaft in einen beliebigen Wert derThreadPriority-Enumeration ändern.

Eine ausführliche Beschreibung der verschiedenen Threadprioritäten finden Sie unter ThreadPriority.

Vordergrund- und Hintergrundthreads

Ein Vordergrundthread wird ohne zeitliche Begrenzung ausgeführt, während ein Hintergrundthread beendet wird, sobald der letzte Vordergrundthread beendet wurde. Den Hintergrundstatus eines Threads können Sie mithilfe der IsBackground-Eigenschaft bestimmen oder ändern.

Multithreading bei Formularen und Steuerelementen

Multithreading eignet sich besonders gut für die Ausführung von Prozeduren und Klassenmethoden, Sie können es aber auch für Formulare und Steuerelemente verwenden. Berücksichtigen Sie dabei folgende Punkte:

  • Die Methoden eines Steuerelements sollten, wenn möglich, nur in dem Thread ausgeführt werden, mit dem das Steuerelement erstellt wurde. Wenn die Methode eines Steuerelements in einem anderen Thread aufgerufen werden muss, müssen Sie die Methode mit Invoke aufrufen.

  • Verwenden Sie die SyncLock-Anweisung (Visual Basic) bzw. die lock-Anweisung (C#)nicht, um Threads zu sperren, die Steuerelemente oder Formulare verarbeiten. Da die Methoden von Steuerelementen und Formularen manchmal einen Rückruf der aufrufenden Prozedur ausführen, verursachen Sie dadurch u. U. unabsichtlich einen Deadlock. Dies ist eine Situation, in der zwei Threads darauf warten, dass der jeweils andere die Sperre wieder aufhebt, sodass die Anwendung angehalten wird.

Siehe auch

Referenz

Threadsynchronisierung (C# und Visual Basic)

Invoke

InvokeRequired

Thread

Konzepte

Parameter und Rückgabewerte für Multithreadprozeduren (C# und Visual Basic)

Weitere Ressourcen

Multithreading in Komponenten

Gewusst wie: Erstellen eines Threads mit Visual C#