Vorheriger Beitrag: Thread Profiler: Parallelisierte Anwendungen grafisch testen
Mögliche Thread-Modi und deren Folgen
Multicore-Programmierung ist sicherlich kein einfaches Ding. Zu viel kann dabei passieren und schiefgehen, wenn man bestimmte Regeln nicht beachtet. Daher starten wir heute einen Mehrteiler, der sich mit den Details der Multicore-Programmierung beschäftigt. Im ersten Teil geht es um die fundamentale Frage, welche Zustände ein Thread während des Programmablaufs annehmen kann.
Im ersten Schritt wird beispielsweise vom Thread Manager ein Thread erzeugt und in den Bereit-Zustand versetzt (“ready”). Dort verharrt der Thread so lange, bis er eine Anweisung, eine Funktion oder ähnliches ausführen soll. Darum kümmern sich entsprechende Programmanweisungen wie zum Beispiel die Pragma-Methoden der OpenMP-basierten Programmierung.
Im zweiten Schritt kommt es zur Ausführung der entsprechenden Quellcodestelle. Währenddessen muss der betreffende Thread möglicherweise auf einen anderen Thread oder ein Datum eines parallel ablaufenden Threads warten. Dann begibt er sich in den Wartend-Modus, bis der benötigte Thread beendet ist oder dessen Ergebnis vorliegt. Anschließend wird der angehaltene Thread weiter ausgeführt oder wieder in den Bereit-Zustand versetzt, da der Thread zu einem späteren Zeitpunkt nochmals benötigt wird.
Ach ja: Gerade dieser Wartend-Modus bereitet vielen Programmierern erhebliche Probleme, da hierbei Dead Locks, Data Races oder andere unvorhersehbare Ereignisse auftreten können. Wie gut, dass es hierfür Tools wie den Thread Checker oder Parallel Inspector gibt, die solche Schwachstellen aufspüren können.
Natürlich ist es auch möglich, dass ein Thread ausgeführt wird, ohne in den Wartend-Zustand versetzt zu werden. Dann stehen zwei Folgemodi zur Auswahl: Bereit oder Beendet. “Bereit” tritt immer dann ein, wenn der Thread nicht nur einmal, sondern mehrmals benötigt wird, was schon beim Programmdesign berücksichtigt werden muss. Dies kann beispielsweise eine Schleife sein, die mehrfach ausgeführt werden muss. In diesem Fall empfiehlt es sich, den zugehörigen Thread nicht zu beenden, sondern ihn wieder auf “Bereit” zu setzen, da das Erzeugen eines Threads relativ viel Rechenzeit und Verwaltungsaufwand bedeutet.
Sobald ein Thread nicht mehr benötigt wird, kann er natürlich auch beendet werden. Er wird dann aus dem Thread-Pool entfernt, alle Variablen werden gelöscht und der Thread steht nicht mehr zur Verfügung. Was aber nicht heißt, dass er zu einem späteren Zeitpunkt nicht wieder erzeugt werden kann.
Übrigens: Zu Beginn einer parallelisierten Anwendung wird ein sogenannter Initial Thread initiert, der den sequeziellen Programmablauf steuert und der auch dafür zuständig ist, das Programm “am Leben zu erhalten”, während zur Laufzeit immer wieder neue, parallel ausfühbare Threads erzeugt werden. Sobald dieser Initialisierungsthread beendet wird, endet auch das komplette Programm.



Trackbacks & Pingbacks