Dies ist die alte 4D Dokumentations-Website. Die neue und aktualisierte Dokumentation finden Sie unter developer.4d.com |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4D v20.6
Preemptive 4D Prozesse
|
Preemptive Ausführung | |
4D Server | X |
4D Remote | X (nur mit ServerNet - siehe Netzwerk-Schicht ServerNet (Kompatibilität)) |
4D Einzelplatz | X |
Kompilierter Modus | X |
Interpretierter Modus | - |
Unterstützt der Ausführungskontext den preemptive Modus und ist die Methode "thread-safe", wird ein neuer 4D Prozess, gestartet über die Befehle New process oder CALL WORKER oder über den Menübefehl "Methode ausführen", in einem preemptive Thread ausgeführt.
Rufen Sie dagegen New process oder CALL WORKER in einem Ausführungskontext auf, der nicht unterstützt wird (z.B. im interpretierten Modus), ist der Prozess immer kooperativ.
4D Code kann nur unter ganz bestimmten Bedingungen in einem preemptive Thread laufen. Jeder Teil des ausgeführten Code (Befehle, Methoden, Variablen) muss mit einer preemptive Ausführung kompatibel sein. Elemente, die in preemptive Threads laufen können, werden thread-safe genannt. Elemente, die nicht in preemptive Threads laufen können, werden thread-unsafe genannt.
Hinweis: Da ein Thread unabhängig von der ihn startenden übergeordneten Prozessmethode verwaltet wird, darf die gesamte Aufrufkette keinen thread-unsafe Code enthalten, da dann keine preemptive Ausführung möglich ist. Weitere Informationen dazu finden Sie im Abschnitt Wann startet ein Prozess preemptive?
Die Eigenschaft "thread-safe" für jedes Element hängt vom Element selbst ab:
Im allgemeinen kann Code, der in preemptive Threads laufen soll, keine Teile mit externen Interaktionen aufrufen, wie Plug-In Code oder Interprozessvariablen. Zugriff auf Daten ist dagegen erlaubt, da der 4D Daten-Server die preemptive Ausführung unterstützt.
4D führt standardmäßig alle Projektmethoden im kooperativen Modus aus. Um die Vorteile des preemptive Modus zu nutzen, müssen Sie zuerst alle Methoden, die nach Möglichkeit im preemptive Modus starten sollen, explizit deklarieren. Das sind die als preemptiv nutzbar geltenden Methoden. Der Compiler prüft, ob solche Methoden tatsächlich thread-safe sind. Weitere Informationen dazu finden Sie im Abschnitt Eine thread-safe Methode schreiben. Bei Bedarf können Sie den preemptive Modus für einige Methoden auch nicht erlauben.
Beachten Sie, dass eine als preemptiv nutzbar deklarierte Methode lediglich für die preemptive Ausführung wählbar ist, aber nicht garantiert, dass sie in Echtzeit tatsächlich im preemptive Modus ausgeführt wird. Ob ein Prozess im preemptive Modus gestartet wird, richtet sich nach der Bewertung, die 4D für die Eigenschaften aller Methoden in der Aufrufkette des Prozesses durchführt. Weitere Informationen dazu finden Sie im Abschnitt Wann startet ein Prozess preemptive?
Im Dialogfenster Methode Eigenschaften gibt es die neue Option Ausführungsmodus, um eine Methode für den preemptive Modus wählbar zu deklarieren:
Es gibt folgende Optionen:
Beim Export des Methoden-Code, z.B. mit METHOD GET CODE, wird die Eigenschaft "preemptiv" im Attribut des Parameters Befehl mit dem Wert "auto", "safe" oder "unsafe" exportiert. Auch die Befehle METHOD GET ATTRIBUTES und METHOD SET ATTRIBUTES erhalten oder setzen das Attribut "preemptiv" mit dem Wert "auto", "safe" oder "unsafe".
Nachfolgende Tabelle zeigt die Auswirkung der verschiedenen Optionen für preemptive Modus:
Option | Wert der Eigenschaft preemptiv (interpretiert) | Compiler Aktion | Internes Tag (kompiliert) | Ausführungsmodus bei thread-safe Kette |
Kann in preemptive Prozessen laufen | Fähig | Prüft die Fähigkeit und gibt Fehler zurück, wenn unfähig | thread-safe | Preemptiv |
Kann nicht in preemptive Prozessen laufen | Unfähig | Keine Bewertung | thread-unsafe | Kooperativ |
Keine Differenzierung | auto | Bewertung, aber keine Fehlermeldung | thread-safe oder thread-unsafe | Wenn thread-safe: preemptiv; wenn thread-unsafe: kooperativ; bei direktem Aufruf: kooperativ |
Zur Erinnerung: Die preemptive Ausführung ist nur im kompilierten Modus möglich.
Beim Starten eines Prozesses, der entweder über New process oder CALL WORKER erstellt wurde, liest 4D im kompilierten Modus die preemptive Eigenschaft der Prozessmethode (auch Eltern Methode genannt) und führt den Prozess je nach definierter Eigenschaft im preemptive oder kooperativen Modus aus:
Die aktuelle Eigenschaft thread-safe richtet sich nach der Aufruffolge. Ruft eine als preemptiv nutzbar deklarierte Methode auf einer ihrer Unterebenen eine thread-unsafe Methode auf, wird ein Kompilierungsfehler zurückgegeben: Ist eine einzelne Methode innerhalb der gesamten Aufruffolge thread-unsafe, kontaminiert sie alle anderen Methoden und der Compiler verweigert die preemptive Ausführung. Ein preemptive Thread lässt sich nur erstellen, wenn die gesamte Aufruffolge thread-safe ist und die Prozessmethode als "Als preemptive Prozess starten" deklariert ist.
Andererseits lässt sich die gleiche thread-safe Methode in einer Aufruffolge in einem preemptive Thread ausführen, in einer anderen Aufruffolge dagegen im kooperativen Thread.
Hier sehen Sie ein paar Beispiele für Projektmethoden:
//Projektmethode MyDialog
//enthält Aufrufe der Oberfläche: ist intern thread unsafe
$win:=Open form window("tools";Palette form window)
DIALOG("tools")
//Projektmethode MyComp
//enthält einfache Berechnung: ist intern thread safe
C_LONGINT($0;$1)
$0:=$1*2
//Projektmethode CallDial
C_TEXT($vName)
MyDialog
//Projektmethode CallComp
C_LONGINT($vAge)
MyCom($vAge)
Nachfolgende Übersicht zeigt die verschiedenen Situationen:
Deklaration und Aufruffolge | Kompilierung | Resultierende Thread Sicherheit | Kommentar | Ausführung |
![]() | OK | ![]() | Methode A ist die übergeordnete Methode, deklariert als preemptive nutzbar; da Methode B intern thread-safe ist, ist Methode A thread-safe und der Prozess preemptiv | Preemptive |
![]() | Fehler | ![]() | Methode C ist die übergeordnete Methode, deklariert als preemptive nutzbar; da aber Methode E intern thread-unsafe ist, kontaminiert sie die Aufruffolge und die Kompilierung schlägt fehl wegen Konflikt mit Methode C. | Die Lösung ist entweder, Methode E thread-safe zu machen (ausgehend, dass Methode D thread-safe ist), so dass die Ausführung preemptive läuft oder im kooperativen Modus zu arbeiten (die Deklaration der Methode C verändern). |
![]() | OK | ![]() | Da Methode F als preemptive nicht nutzbar deklariert ist, ist die Kompilierung intern thread-unsafe, die Ausführung läuft immer kooperativ, egal welchen Status Methode G hat. | Kooperativ |
![]() | OK | ![]() | Da Methode H die übergeordnete Methode ist (Eigenschaft "Automatisch wählen"), ist der Prozess kooperativ. Die Kompilierung ist erfolgreich, selbst wenn Methode I als preemptive nutzbar deklariert ist | Kooperativ |
![]() | OK | ![]() | Methode J ist die übergeordnete Methode (Eigenschaft "Nicht-zugeordnet"), der Prozess ist dann kooperativ, selbst wenn die gesamte Aufruffolge thread-safe ist | Kooperativ |
4D ermöglicht, den Ausführungsmodus für Prozesse im kompilierten Modus herauszufinden:
Prozesstyp | Icon |
Preemptive Serverprozedur | ![]() |
Preemptive Worker Prozess | ![]() |
Preemptive Web Methode | ![]() |
Preemptive SOAP Methode | ![]() |
Für eine thread-safe Methode gelten folgende Regeln:
Hinweise:
(*) Für den Datenaustausch zwischen preemptive Prozessen (und zwischen allen Prozessen) können Sie shared collections oder shared objects als Parameter an Prozesse übergeben bzw. den Katalog Storage verwenden. Weitere Informationen dazu finden Sie auf der Seite Shared Objects und Shared Collections.
Auch Worker Prozesse ermöglichen, Daten zwischen allen Prozessen auszutauschen, inkl. preemptive Prozesse. Weitere Informationen dazu finden Sie im Abschnitt Über Worker.
(**) Der Befehl CALL FORM bietet eine elegante Lösung, um Objekte der Oberfläche aus einem preemptive Prozess aufzurufen.
4D überprüft Methoden mit der Eigenschaft "Als preemptive Prozess starten" auch beim Kompilieren. Findet der Compiler etwas, das thread-safe verhindert, wird ein Kompilierungsfehler ausgegeben:
Hinweis: Die Überprüfung von Thread-Sicherheit lässt sich lokal deaktivieren, siehe unten Überprüfung von Thread-Sicherheit lokal deaktivieren)
Ist die Symbol Datei aktiviert, zeigt sie für jede Methode den Status der Thread-Sicherheit:
Aufrufen von Objekten der Benutzeroberfläche, z.B. Formulare oder Öffnen des Debuggers sind externe Zugriffe und deshalb in preemptive Threads nicht erlaubt.
Die Benutzeroberfläche ist von einem preemptive Thread aus nur in folgenden Fällen verwendbar:
Eine beträchtliche Anzahl von 4D Befehlen sind thread-safe. Bei den Befehlen im Handbuch 4D Programmiersprache zeigt das Icon im Bereich Eigenschaften rechts oben an, dass dieser Befehl thread-safe ist. Klicken Sie auf das Icon, erscheint die Liste der thread-safe Befehle.
Die Funktion Command name kann die Eigenschaft Thread-Sicherheit für jeden Befehl zurückgeben (siehe unten).
Bei einer Methode mit einem Befehl, der Trigger aufrufen kann, bewertet der 4D Compiler zum Überprüfen der Thread-Sicherheit der Methode die Thread-Sicherheit des Trigger:
SAVE RECORD([Table_1]) //Trigger auf Table_1, wenn vorhanden, muss thread-safe sein
Hier die Liste der Befehle, die beim Kompilieren auf Thread-Sicherheit des Trigger geprüft werden:
Bei dynamischer Übergabe der Tabelle findet der Compiler manchmal nicht den Trigger zum Überprüfen heraus. Hierzu Beispiele:
DEFAULT TABLE([Table_1])
SAVE RECORD
SAVE RECORD($ptrOnTable->)
SAVE RECORD(Table(myMethodThatReturnsATableNumber())->)
In diesem Fall werden alle Trigger geprüft. Wird in mindestens einem Trigger ein thread-unsafe Befehl gefunden, wird die ganze Gruppe abgewiesen und die Methode als thread-unsafe deklariert.
Fehlerverwaltungsmethoden, die über den Befehl ON ERR CALL eingerichtet werden, müssen thread-safe sein, wenn sie von einem preemptive Prozess aufgerufen werden sollen. Für diesen Fall prüft der Compiler jetzt beim Kompilieren die Eigenschaft thread-safe der Fehlerverwaltungsmethoden im Befehl ON ERR CALL und gibt entsprechende Fehler zurück, wenn sie nicht zur preemptive Ausführung passen.
Beachten Sie, dass diese Prüfung nur möglich ist, wenn der Methodenname als Konstante übergeben ist und nicht berechnet wird, wie unten angezeigt:
ON ERR CALL("myErrMethod1") //wird vom Compiler geprüft
ON ERR CALL("myErrMethod"+String($vNum)) //wird vom Compiler nicht geprüft
Außerdem wird ab 4D v15 R5 der neue Fehler -10532 generiert, wenn sich eine Fehlerverwaltungsmethode nicht in Echtzeit aufrufen lässt (bei Unstimmigkeiten der Thread-Sicherheit oder aus einem anderen Grund, wie z.B. Methode wurde nicht gefunden). Die Fehlermeldung lautet: "Kann nicht die Projektmethode 'MethodeName' zur Fehlerverwaltung aufrufen".
Ein Prozess kann einen Zeiger nur dereferenzieren, um auf den Wert einer anderen Prozessvariable zuzugreifen, wenn beide Prozesse kooperativ sind. Sonst gibt 4D einen Fehler zurück. Versucht 4D Code in einem preemptive Prozess einen Zeiger auf eine Interprozessvariable zu dereferenzieren, gibt 4D einen Fehler aus.
Beispiel mit folgenden Methoden:
Methode1:
myVar:=42
$pid:=New process("Methode2";0;"Prozessname";->myVar)
Methode2:
$value:=$1->
Ist der Prozess mit Methode1 oder der Prozess mit Methode2 preemptive, gibt der Ausdruck "$value:=$1->" einen Ausführungsfehler aus.
Der Parameter DocRef (geöffnete Dokumentreferenz, von Open document, Create document, Append document, CLOSE DOCUMENT, RECEIVE PACKET, SEND PACKET verwendet oder zurückgegeben) lässt sich folgendermaßen verwenden:
Weitere Informationen dazu finden Sie im Abschnitt DocRef: Referenznummer des Dokuments.
Es kann Fälle geben, wo Sie die Überprüfung von Thread-Sicherheit auf bestimmte Teile des Code nicht anwenden wollen, z.B. wenn dieser Befehle enthält, die zwar nicht thread-safe sind, jedoch nie aufgerufen werden.
Dazu müssen Sie den Code, der nicht geprüft werden soll, mit den spezifischen Direktiven %T- und %T+ als Kommentare umrahmen. Die Direktive //%T- deaktiviert die Überprüfung von Thread-Sicherheit, die Direktive //%T+ aktiviert sie wieder:
// %T- Überprüfung von Thread-Sicherheit deaktivieren
// Setzen Sie hier den Code mit Befehlen, die nicht auf Thread-Sicherheit geprüft werden sollen
$w:=Open window(10;10;100;100) //Beispiel
// %T+ Überprüfung von thread-Sicherheit für die restliche Methode wieder aktivieren
Natürlich muss der 4D Entwickler selbst für die Kompatibilität der preemptive Ausführung von Code zwischen den Direktiven für Deaktivierung und Reaktivierung sorgen. Bei Ausführen von thread-unsafe Code in einem preemptive Thread treten Runtime Fehler auf.
Produkt: 4D
Thema: Prozesse
Erstellt: 4D v15 R5
4D Programmiersprache ( 4D v20)
4D Programmiersprache ( 4D v20.1)
4D Programmiersprache ( 4D v20.2)
4D Programmiersprache ( 4D v20.3)
4D Programmiersprache ( 4D v20.4)
4D Programmiersprache ( 4D v20.5)
4D Programmiersprache ( 4D v20.6)