Procedure of Thread
Durch diese Maßnahme würde Lazarus/FPC zu einer Programmier-Umgebung erweitert die (wie ADA, nur besser

– vorläufiges Konzept –
Es wird ein neues Sprachelement „of Thread“ definiert, das syntaktisch wie „of Object“ bei der Deklaration von Typen von Prozeduren und Funktionen verwendet werden kann.
Die Verwendung einer „Procedure of Thread“ oder „Function of Thread“ als Ereignis lässt beim „Feuern“ den Handler des Ereignisses im Kontext des Threads ablaufen, der die Ereignis-Variable gesetzt hat. (Solche Events sollen dan "Thread-Event" genannt werden.) Als Spezialfall wird die Funktionsweise von TThread.Synchronize reproduziert.
Im Detail bewirkt eine Element vom Typ „Procedure of Thread“ oder „Function of Thread“ folgendes:
Als Variable oder Property kann es wie ein Element „of Object“ verwendet werden, um einen Ereignis-Handler zu definieren. Bei der Zuweisung wird (wie bei „of Object“) die Adresse des Einsprung-Punktes und der aktuelle Self-Pointer gespeichert. Zusätzlich wird noch eine Kennung für den aktuell laufenden Thread gespeichert. Eine Variable vom Typ „of Thread“ besteht also (vermutlich) aus drei Doppelworten.
Wird eine Funktion oder Prozedur vom Typ „of Thread“ aufgerufen (i. A. unter Verwendung einer „of Thread“ - Variablen) geschieht folgendes:
Ist der aktuelle Thread gleich des in der Variablen gespeicherten Threads (oder wird eine „of Thread“ Funktion/Prozedur direkt – ohne Verwendung einer Event-Variablen – aufgerufen), wird der Event-Handler als normale Funktion aufgerufen.
Anderenfalls wird eine Struktur angelegt, die die Aktual-Parameter repräsentiert (hier wird verfahren wie bei RPC-Mechanismen üblich). Diverse Probleme sind hier zu beachten:
- es wird eine neue Aufrufkonvention („RPC“ oder so ähnlich) verwendet, also nicht „Register“ „RPCCall“ u.s.w.
- Bei dem Namen nach übergebene Const- und Var- Parameter und Objekttypen wird vermutlich einfach der Pointer verwendet.
- Es kann natürlich sein, dass vor der Bearbeitung durch den anderen Thread die Struktur bereits gefreed ist. Idealer Weise sollte (bei Bedarf) durch einen reference counting Mechanismus sichergestellt werden, dass so etwas nicht passiert. Vielleicht sollten nur reference counted Typen (wie String und Interface und vielleicht ein neuer automatischer Typ, der reference counted 8/16/32/64 Bit Numerics und Floating Points darstellen kann) zugelassen werden (bei teilweise automatischer Konvertierung von Standard-Typen: Zahl -> reference counted Zahl, Klasse -> Interface).
- Pointer auf lokale (Stack-) Variablen sind verboten (sollten explizite Pointer erlaubt sein ?).
- Variants sind vermutlich reference counted ????
- vielleicht ist die „In“ und „Out“ Syntax für Parameter sinnvoller als zu versuchen „Value“, Const, und Var -Parameter automatisch zu behandeln.
- Die Übergabe des Funktionswertes erfolgt wie bei einem Var-Parameter. Die Kennung ob eine Funktionswert verlangt wird, wird bei Funktionen als zusätzlicher Parameter in der RPC-Struktur gehalten. Weiteres zu Funktions-Rückgabe-Werte siehe unten.
Wenn beim Aufruf ein Funktionswert verlangt wird, wird der aufrufende Thread angehalten bis der gerufene Thread das Ereignis abgearbeitet hat (analog der „Synchronize“ - Methode von TThread). (Das kann leicht durch eine Semaphore realisiert werden.) Da der rufende Thread blockiert ist, wird die blockierende Ressource als zusätzlicher Parameter an den aufgerufenen Thread übergeben. Bei Prozeduren und wenn eine Funktion wie eine Prozedur (ohne „:=“) aufgerufen wird, läuft der aufgerufene Thread parallel mit dem aufrufenden. (Wenn als ein Wert aus einem parallel laufenden Thread zurückgegeben werden soll geht das nur mit einem Var-oder „Out“ Parameter.)
Es wird eine Message generiert und an den aufzurufenden Thread geschickt (hierzu muss dieser Thread natürlich mit einer Message-Queue ausgestattet sein ). Die Message enthält die Referenz auf die RPC-Parameter-Struktur.
wird die Message aus der Queue bearbeitet, extrahiert der empfangende Thread die Parameter aus der Parameterstruktur und ruft den Usercode des Event-Handlers auf.
Nach Rückkehr aus dem User-Code wird (falls angefordert) die Ressource freigegeben, die den aufrufenden Thread blockiert.
Frage: ist es sinnvoll eine Möglichkeit zu schaffen, einen anderen als den aktuellen Thread als aufzurufenden Thread zu vermerken ? Die Syntax hierzu müsste vermutlich stark von der Standard-Syntax abweichen.
Es wäre schön, die Definition und den Start der zusätzlichen Threads nicht im User-Code machen zu müssen. Hier bietet sich der Objekt-Quelltext an, um analog zu „Application.Init“ und „Application.Run“ für alle vordefinierten Threads einen Block erzeugen der (für x = 1,...n) in etwas so aussehen könnte:
Code: Alles auswählen
ApplicationThreadx := TApplicationThread.create;
ApplicationThreadx.Init; // Falls das notwendig ist
ApplicationThreadx.Run;
Code: Alles auswählen
Procedure ApplicationThreadx.Execute;
begin
// place the code for starting your Application Thread here
end;
Ich freue mich über weitere Anregungen.
-Michael