Workshop: Alles über .NET-Threads – Teil 3

veröffentlicht von am 12. März 2009

Teil eins und Teil zwei meines Minispecials zum Thema .NET-Threads stehen bereits online, und heute folgt sehr chronologisch der dritte Abschnitt. Dieser handelt von den Thread-Pools, mit deren Hilfe eine größere Anzahl von notwendigen Threads mithilfe des .NET-Frameworks verwaltet werden können.

Zunächst einmal sollte man sich klar machen, dass das Erzeugen und Verwalten von .NET-Threads mit einem immensen administrativen Aufwand verbunden ist: Lokaler Thread-Speicher muss angelegt und die Systemstrukturen für die Thread-Verwaltung müssen eingerichtet werden. Darüber hinaus nimmt die Komplexität des Quellcodes deutlich zu, sobald mehrere Threads mit Bordmitteln verwaltet werden sollen.

Aus diesem Grund hat Microsoft dem .NET-Framework ein Ressource spendiert, die sich ThreadPool nennt. Dabei wird zunächst eine bestimmte Anzahl von Threads generiert, außerdem wird eine Art Arbeitswarteschlange erstellt. Sobald eine auszuführende Aufgabe in diese Warteschlange befördert wird, wird ein Thread für diesen Task aktiviert und ihm die Aufgabe zugewiesen. Dies erledigt das .NET-Framework automatisch. Allerdings ist dabei zu beachten, dass der ThreadPool nur dann sinnvoll eingesetzt werden kann, wenn ein Programm aus mehreren Threads besteht, die immer wieder benötigt werden.

Der Pool wird mithilfe der Anweisung ThreadPool.QueueUserWorkItem (new WaitCallback ( DELEGAT ) ) erzeugt, sobald die erste Aufgabe an die Warteschlange übergeben wird. Die Anzahl der im Pool erzeugbaren Threads ist unter .NET auf 25 pro Hardware-Prozessor begrenzt. Allerdings kann man mithilfe der Methoden GetMinThreads() und SetMinThreads() die minimale Anzahl von Threads abfragen bzw. erzwingen. Mit GetMaxThreads() lässt sich die maximale Anzahl von Threads bestimmen.

Mit den ThreadPools in .NET lassen sich aber nicht nur Aufgaben parallel ausführen, sondern auch asynchrones Warten erzwingen. So kann beispielsweise auf einen Datenanfrage innerhalb des Netzwerks reagiert werden. Hierfür ist eine sogenannte Callback-Funktion erforderlich, die beim Eintreten eines zu erwartenden Ereignisses aufgerufen wird. Eine dieser Funktionen nennt sich RegisterWaitForSingleObjekct(), die die Angabe einer maximalen Wartezeit erlaubt. Die Callback-Funktion wird aufgerufen, wenn das Ereignis eintritt oder die definierte Wartezeit abgelaufen ist.

Aber nicht nur einzelne Ereignisse können Threads starten, sondern auch eine ganze Reihe davon. Hierfür existieren die Methoden WaitHandle.WaitAll() und WaitHandle.WaitAny(), die ausgeführt werden, wenn alle Ereignisse oder irgendein Ereignis eintreten. Zudem lassen sich diese manuell mithilfe der Methode ManualResetEvent() zurücksetzen.


Kategorien : Multicore Tags : , ,

Kommentare
Beitrag kommentieren.

Sie müssen angemeldet sein um diesen Beitrag zu kommentieren. [Login | Registrieren]

(erforderlich)

(erforderlich)