Das Builder Tutorial
Inhaltsverzeichnis Threads VCL-Thread

VCL-Thread

Als ersten Schritt erstellen wir erst einmal ein neues Projekt in der C++ Builder IDE. Falls Sie mit dem Erstellen von Projekten und weiteren Grundlagen noch nicht vertraut sind, lesen Sie bitte erst einmal das Kapitel über die C++ Builder Grundlagen, ebenfalls in diesem Tutorial. Wie weiter oben bereits beschrieben, erstellen wir zusammen mit dem Assistenten ein Thread-Objekt dem wir den Namen "TMyThread" zuweisen. Ihr Projekt sollte nun im Projekt-Explorer folgendes Aussehen haben:

Abb. 3: Projektstand


Für das Formular benötigen wir:

2 TButton (ThreadDispButton, DispButton)
1 TLabel (DispLabel)

Die Anordnung der Elemente sieht bei mir wie in Abb. 4 aus, diese kann aber auch abweichen:


Abb.4: Die Testoberfläche


Als nächstes erstellen wir per Doppelklick auf den Schalter "Bsp. Ohne Thread" eine Ereignis-Routine die wir folgendermaßen ausprogrammieren:
Erzeugen Sie nun das Programm und führen es aus. Klicken Sie einmal auf den Schalter und versuchen Sie nun, während das Programm rechnet, das Fenster zu verschieben bzw. es in der Größe zu verändern und achten Sie auf die Anzeige des DisplayLabel! Richtig, während das Programm rechnet, kann weder das Programm verschoben noch in der Größe verändert werden, auch an der Anzeige des DisplayLabel tut sich überhaupt nichts. Ist die Berechnung vorbei (dies kann je nach verwendeter Hardware differieren), zeigt der DisplayLabel den aktuellen Wert von i an, standardmäßig 200 000.
Dieses Programm führt deutlich vor Augen, das dieses Programm so lange blockiert ist, bis die Arbeit getan ist, erst danach kann der Anwender mit dem Programm weiterarbeiten. Damit aber nicht jede Anwendung, die eine rechenintensive Funktion beherbergt, zur komplexen Multithread Anwendung ausgebaut werden muss, schafft hier der Aufruf einer Funktion des Application Objekts Abhilfe:

Application->ProcessMessages();

Dieser Aufruf sorgt nun dafür, dass nach jedem Schleifendurchlauf Windows die Botschaftswarteschlange verarbeiten kann. Also auch die Botschaften, ob das Fenster verschoben oder in der Größe verändert wird. Sogar der DisplayLabel wird nun aktualisiert. Sind Threads also überflüssig, kann man alles mit diesem Aufruf erledigen? Nein, natürlich nicht. Denn auch dieser Aufruf hat, wenngleich er einiges an Verbesserung der Situation bietet, einen gewaltigen Pferdefuß.

Starten Sie die Berechnung noch einmal und verschieben Sie, während gerechnet wird, das Formular auf dem Monitor. Was passiert? Während das Formular verschoben wird, wird die Berechnung unterbrochen, selbst ein Klick auf das Schließen-Symbol wird nicht ausgeführt, erst nachdem die Berechnung fertig ist. Auch könnte der Anwender mehrmals auf den Schalter klicken, was hier zur Folge hätte, das die Berechnung mehrmals hinter einander durchgeführt wird. Als Resultat können wir festhalten, das der Aufruf von "ApplicationProcessMessages" zwar für kleinere Dinge wie das Neuzeichnen von Oberflächenelementen bzw. Empfangen der Windows-Botschaften gute Dienste tut, jedoch nicht das liefert, was wir im Endeffekt erreichen wollen.

Implementieren wir nun dieselbe Funktionalität innerhalb einer Thread-Klasse. Wechseln Sie zur Klassendeklaration des neuen, abgeleiteten Threads und ergänzen Sie diese folgendermaßen:


Die Originalklasse des Assistenten wird also um die Membervariable FCount und die Methode Display() ergänzt. Die Variable benötigen wir als Durchlaufzähler und Display() verwenden wir für die Aktualisierung der Anzeige des DiaplayLabel auf Form1. Im Konstruktor setzen wir die Eigenschaft FreeOnTerminate = true, somit wird der Thread freigegeben, sobald die Methode Terminate() aufgerufen wird:


Die Methode Execute() hat der Assistent bereits für uns angelegt. Es handelt sich hierbei quasi um das Hauptprogramm eines Threads. Execute ist eine virtuelle Methode die in der Basisklasse noch abstrakt ist. Wir ergänzen Sie nun:

Wir wechseln nun nach Unit1 und fügen per Doppelklick auf den Schalter "Bsp. mit Thread" der Unit eine neue Ereignis-Routine hinzu:

Dieser Quelltext reicht aus, um den Thread zu starten. Sobald der Konstruktor aufgerufen wird und diesem der Parameter false (für CreateSuspended) übergeben wird, startet der Thread bzw. dessen Methode Execute().

Nun kommen wir zum Untersuchen des Programms. Kompilieren Sie alles und starten den Thread führen Sie bei laufender Berechnung die selben Aktionen durch wie vorher.

Resultat 1: Wir können nun problemlos das Formular verschieben und in der Größe ändern, die Berechnung wird fortgesetzt und die Anzeige ist immer aktuell.

Resultat 2: Ein Klick auf das Schließen-Symbol beendet die Anwendung unmittelbar.

Was kann man daraus folgern? Ganz einfach, das der Prozessor zwischen den beiden Threads (VCL-Hauptthread und TmyThread) seine Zeit aufteilt und hin und her wechselt. Und da der Prozessor ein verdammt flinkes Kerlchen ist, kommt es uns Menschen so vor, als wenn er beide Aufgaben gleichzeitig durchführt (hierbei kommt es natürlich noch darauf an, was für einen Prozessor man sein eigen nennt).
Um dieses hin und her wechseln, also das Aufteilen der Prozessorzeit sichtbarer zu machen, können Sie die Schalterroutine ein wenig ausbauen:

Nach dem Start sehen Sie, dass sowohl der Thread ausgeführt wird, als auch das Hauptprogramm (da während der Thread läuft, nacheinander beide MessageBoxen ausgegeben werden). Damit der Thread aber auch sauber "zerstört/entfernt" wird, ergänzen wir die Methode noch um folgende Zeile:

In der Methode, die dem Ereignis OnTerminate zugewiesen wird, kann der gesamte Clean-Up-Code des Threads geschrieben werden.

Mit diesen Zeilen stellen wir nun sicher, dass der Thread ordnungsgemäß entsorgt wird, sobald die Zählervariable Fcount den Wert 200 000 erreicht hat. Wird die Anwendung aber beendet, bevor dies geschehen ist, wird der Thread nicht freigegeben. Hierfür schreiben wir noch etwas Code in das OnClose-Ereignis des Formulars:

Somit wäre dafür Sorge getragen, das der Thread sauber entsorgt wird. Setzen Sie doch einmal einen Debugger-Haltepunkt in die Methode DeleteThread(...) und starten Sie den Thread. Sie werden sehen, dass das Programm bei Erreichen von 200.000 sofort den Thread terminiert und freigibt (da wir im Konstruktor FreeOnTerminate = true gesetzt haben).

Rück Vor Zum Seitenanfang


Seite drucken Das Builder Tutorial im Netz  

Urheberrecht © Das Builder Tutorial Team. Alle Rechte vorbehalten.

letzte Aktualisierung: