Deadlock und Race Condition

Teil 3: Programmieren für die Multi-Core-CPU

Multithreading in .NET

Obgleich das .Net-Framework von Microsoft für multithreaded Umgebungen ausgelegt ist, so gilt das natürlich nur für das Framework. Um seinen eigenen Code muss sich der Entwickler bei der Programmierung jedoch selbst kümmern. Threading, also die Programmierung von parallelen Applikationen, ist auch in .Net keine einfache Angelegenheit.

Wenn bis dato immer von der Softwareentwicklung im Allgemeinen gesprochen wurde, so gilt das genauso für den gesamten Entwicklungsprozess, also die Modellierung, die Codierung und auch den begleitenden Module- oder Integrationstest. Beachtet werden muss ferner, dass derzeit nahezu alle, den Entwicklungsprozess begleitenden Hilfen, von streng sequentiell abgearbeiteten Programmen ausgehen.

Suche nach parallelisierbaren Codeabschnitten

Der erste Schritt in der Entwicklung von parallel laufenden Programmen ist die Suche nach all den Codestücken, die parallel abgearbeitet werden können. Hierbei lassen sich meist zwei Techniken der Parallelisierung herausbilden, die Task Parallelisierung und die Daten Parallelisierung.

Bei der Task Parallelisierung wird der Code in zwei oder mehr unabhängige Tasks zerlegt. Diese werden zur Laufzeit als zwei oder mehr unabhängige Threads oder Prozesse abgearbeitet. Als Beispiel dafür mag die Rechtschreibkorrektur des Testsystems gelten. Bezogen auf ein Bestellsystem könnte das Laden der Kundenstammdaten nach der Eingabe der Kundennummer als eigener Task ausgeführt sein.

Bei der Daten Parallelisierung geht man davon aus, dass die durch den Task bearbeiteten Daten völlig separiert sind. Ein Beispiel dafür ist das Rendering von Graphiken oder aufwändigen Bildschirminhalten.

Die Parallelisierung von Code darf aber auch nicht auf eine bestimmt Anzahl CPUs eingeschränkt werden. Vielmehr muss der Code so ausgelegt sein, dass er eine beliebige Anzahl an CPUs nutzen kann. Dies ist deswegen notwendig, da zukünftige CPUs mit noch mehr Kernen ausgestattet sein werden. Die Grenzen der Tasks müssen also dynamisch bestimmt werden. Zumindest aber sollte der Task zur Laufzeit ermitteln, ob es überhaupt sinnvoll ist, ihn auf mehrere CPU-Kerne zu verteilen und parallel auszuführen. Doch dazu müssen bereits im Code die Vorkehrungen eingebaut sein.