Vous êtes sur le site Web historique de la documentation de 4D. Les documentations sont progressivement déplacées vers developer.4d.com |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4D v20.6
Process 4D préemptifs
|
Exécution en préemptif | |
4D Server | X |
4D distant | X (uniquement avec ServerNet - voir Couche réseau ServerNet (compatibilité)) |
4D local | X |
Mode compilé | X |
Mode interprété | - |
Si le contexte d'exécution prend en charge le mode préemptif et si la méthode est "thread-safe", un process 4D lancé à l'aide de la commande Nouveau process ou APPELER WORKER, ou via la commande de menu "Exécuter méthode", sera exécuté dans un thread préemptif.
Sinon, si vous appelez Nouveau process ou APPELER WORKER depuis un contexte d'exécution qui n'est pas pris en charge (i.e. depuis le mode interprété), le process sera toujours coopératif.
Le code 4D code peut être exécuté en mode préemptif uniquement lorsque certaines conditions sont réunies. Chaque partie du code exécution (commandes, méthodes, variables, etc.) doit être compatible avec une utilisation en mode préemptif. Les éléments éligibles au mode préemptif sont qualifiés de thread-safe et ceux qui ne sont pas éligibles au mode préemptif sont qualifiés de thread-unsafe.
Note : Comme un thread est traité de manière indépendante à partir de la méthode du process parent, la totalité de la chaîne d'appel ne doit contenir aucun élément thread-unsafe ; sinon, l'exécution en mode préemptif ne sera pas possible. Ce point est abordé en détail dans le paragraphe Quand un process est-il démarré en préemptif ?.
La propriété "thread safe" de chaque élément dépend de l'élément lui-même :
Fondamentalement, le code destiné à être exécuté dans des threads préemptifs ne peut pas appeler d'éléments ayant des interactions extérieures telles que du code de plug-in ou des variables interprocess. L'accès aux données, cependant, est possible car le serveur de données de 4D prend en charge l'exécution en mode préemptif.
Par défaut, 4D exécute toutes les méthodes projet de vos applications en mode coopératif. Si vous voulez bénéficier de la fonctionnalité du mode préemptif, la première étape consiste à déclarer explicitement toutes les méthodes que vous souhaitez démarrer en mode préemptif à chaque fois que c'est possible -- c'est-à-dire, les méthodes que vous estimez adaptées à une exécution dans un process préemptif. Le compilateur vérifiera que ces méthodes sont réellement thread-safe (voir Ecrire une méthode thread-safe pour plus d'informations). Vous pouvez également interdire le mode préemptif pour certaines méthodes, si nécessaire.
Gardez à l'esprit que déclarer une méthode "capable" d'être utilisée en préemptif la rend éligible à l'exécution dans un process préemptif mais ne garantit pas qu'elle sera effectivement exécutée en mode préemptif dans l'application. Le démarrage d'un process en mode préemptif résulte d'une évaluation effectuée par 4D en fonction de toutes les méthodes de la chaîne d'appel du process (pour plus d'informations, veuillez vous reporter au paragraphe Quand un process est-il démarré en préemptif ?).
Pour déclarer une méthode éligible à l'exécution en mode préemptif, vous devez sélectionner l'option de déclaration Mode d'exécution dans la boîte de dialogue Propriétés de la méthode :
Les options suivantes sont proposées :
Cas particulier : Si la méthode possède également la propriété Partagée entre composants et base hôte (voir Propriétés des méthodes projet), l'option Indifférent marquera automatiquement la méthode comme étant thread-unsafe. Si vous souhaitez qu'une méthode de composant partagé soit thread-safe, vous devez explicitement lui attribuer l'option Peut être exécutée dans un process préemptif.
Lorsque vous exportez le code de la méthode à l'aide, par exemple, de METHODE LIRE CODE, la propriété "preemptive" est exportée dans le commentaire "%attributes" avec la valeur "capable" ou "incapable" (la propriété n'est pas présente si l'option est "Indifférent"). Les commandes METHODE LIRE ATTRIBUTS et METHODE FIXER ATTRIBUTS permettent également de lire ou de fixer l'attribut "preemptive" avec les valeurs "indifferent", "capable" ou "incapable".
Le tableau suivant résume les effets des options de déclaration du mode préemptif :
Option | Valeur de la propriété "preemptive" (interprété) | Action du compilateur | Etiquette interne (compilé) | Mode d'exécution si la chaîne d'appel est thread-safe |
Peut être exécutée dans un process préemptif | capable | Vérifie la compatibilité et retourne des erreurs si incompatible | thread-safe | Préemptif |
Ne peut pas être exécutée dans un process préemptif | incapable | Aucune évaluation | thread-unsafe | Coopératif |
Indifférent | indifferent | Evaluation mais pas d'erreurs | thread-safe ou thread-unsafe | Si thread-safe : préemptif ; si thread-unsafe : coopératif ; si appelée directement : coopératif |
Rappel : L'exécution en mode préemptif est disponible en mode compilé uniquement.
En mode compilé, lorsqu'un process est créé par la commande Nouveau process ou APPELER WORKER, 4D examine la propriété "preemptive" de la méthode du process (aussi appelée méthode parente) et exécute le process en mode préemptif ou coopératif en fonction de cette propriété :
La propriété thread-safe dépend en fait de la chaîne d'appel. Si une méthode déclarée "capable" appelle une méthode thread-unsafe à n'importe lequel de ses sous-niveaux, une erreur sera retournée à la compilation : si une seule méthode de la chaîne d'appel est thread-unsafe, elle "contaminera" toutes les autres méthodes et l'exécution en préemptif sera rejetée par le compilateur. Un thread préemptif ne peut être créé que lorsque la totalité de la chaîne est thread-safe et que l'option "Peut être exécutée dans un process préemptif" a été sélectionnée pour la méthode process.
D'un autre côté, une même méthode thread-safe peut être exécutée dans un thread préemptif dans une première chaîne d'appel, et dans un thread coopératif dans une seconde chaîne d'appel.
Par exemple, considérons les méthodes projet suivantes :
//Méthode projet MyDialog
//contient des appels d'interface : elle sera thread-unsafe en interne
$win:=Creer fenetre formulaire("tools";Form fenêtre palette)
DIALOGUE("tools")
//Méthode projet MyComp
//contient des calculs simples : elle sera thread-safe en interne
C_ENTIER LONG($0;$1)
$0:=$1*2
//Méthode projet CallDial
C_TEXTE($vName)
MyDialog
//Méthode projet CallComp
C_ENTIER LONG($vAge)
MyComp($vAge)
L'exécution d'une méthode en mode préemptif dépendra de sa propriété "execution" et de la chaîne d'appel. Le tableau suivant illustre les diverses situations:
Déclaration et chaîne d'appel | Compilation | Propriété thread safety résultante | Mode d'exécution | Commentaire |
![]() | OK | ![]() | Préemptif | CallComp est la méthode parente, déclarée "capable" pour le préemptif ; comme MyComp est thread-safe en interne, CallComp est thread-safe donc le process peut être préemptif |
![]() | Erreur | ![]() | Exécution impossible | CallDial est la méthode parente, déclarée "capable" ; MyDialog est "indifferent". Cependant, puisque MyDialog est thread-unsafe en interne, elle contamine la chaîne d'appel. La compilation échoue à cause du conflit entre la déclaration de CallDial et ses capacités réelles. La solution est soit de modifier MyDialog afin qu'elle devienne thread-safe de manière à obtenir une exécution en préemptif, soit de changer la propriété de déclaration de CallDial pour lancer un process coopératif |
![]() | OK | ![]() | Coopératif | Comme CallDial est déclarée "incapable" pour le préemptif, sa propriété interne est thread-unsafe ; son exécution sera toujours en coopératif, quel que soit le statut de MyDialog |
![]() | OK | ![]() | Coopératif | Comme CallComp est la méthode parente (propriété "Indifferent"), le process est coopératif même si toute la chaîne d'appel était thread-safe |
![]() | OK | ![]() | Coopératif | CallDial est la méthode parente (propriété "Indifferent"), donc le process est coopératif et la compilation réussit |
4D vous permet d'identifier le mode d'exécution des process en compilé :
Type de process | Icône |
Procédure stockée préemptif | ![]() |
Process worker préemptif | ![]() |
Méthode Web préemptive | ![]() |
Méthode SOAP préemptive | ![]() |
Pour être thread-safe, une méthode doit respecter les conditions suivantes :
Notes :
(*) Pour échanger des données entre des process préemptifs (et entre tous les types de process) vous pouvez utiliser des objets partagés ou des collections partagées, ou encore le catalogue Storage. Pour plus d'informations, reportez-vous à la page Objets partagés et collections partagées.
Les process de type Worker vous permettent également d'échanger des données entre n'importe quel process, y compris des process préemptifs. Pour plus d'informations, reportez-vous à la section A propos des workers.
(**) La commande APPELER FORMULAIRE fournit une solution élégante permettant d'appeler des objets d'interface depuis un process préemptif.
Les méthodes pour lesquelles la propriété "Peut être exécutée dans un process préemptif" a été cochée seront vérifiées par 4D durant la compilation. Une erreur de compilation est générée à chaque fois que le compilateur détecte un élément non compatible avec la propriété thread-safe :
Note : Il est possible de désactiver localement la vérification thread-safety, veuillez consulter Désactiver localement la vérification thread safety ci-dessous).
Le fichier de symboles, s'il est activé, contient également le statut thread safe pour chaque méthode :
Puisqu'il s'agit d'accès "externes", les appels aux objets d'interface utilisateur tels que les formulaires ou le Débogueur ne ne sont pas possibles dans les threads préemptifs.
Les seuls accès à l'interface utilisateur autorisés depuis un thread préemptif sont :
Un nombre important de commandes 4D sont "thread-safe". Dans la documentation, l'icône située dans la zone de propriété de commande indique que la commande est thread-safe. Vous pouvez obtenir la liste des commandes thread-safe en cliquant sur cette icône dans le manuel Langage.
Vous pouvez également utiliser la commande Nom commande qui peut retourner la valeur de la propriété "thread-safe" pour chaque commande.
Lorsqu'une méthode utilise une commande pouvant potentiellement déclencher un trigger, le compilateur de 4D évalue la propriété "thread-safe" du trigger afin de déterminer la compatibilité de la méthode avec le mode préemptif :
STOCKER ENREGISTREMENT([Table_1]) //le trigger sur Table_1, s'il existe, doit être thread-safe
Voici la liste des commandes qui entraînent l'analyse du trigger à la compilation :
Si la table est passée dynamiquement, il est possible que le compilateur ne soit pas en mesure de déterminer le trigger à évaluer. C'est le cas par exemple dans les situations suivantes :
TABLE PAR DEFAUT([Table_1])
STOCKER ENREGISTREMENT
STOCKER ENREGISTREMENT($ptrOnTable->)
STOCKER ENREGISTREMENT(Table(myMethodThatReturnsATableNumber())->)
Dans ce cas, tous les triggers sont évalués. Si une commande thread-unsafe est détectée dans au moins un trigger, l'ensemble est rejeté et la méthode est déclarée thread-unsafe.
Les méthodes d'interception d'erreurs installées par la commande APPELER SUR ERREUR doivent être thread-safe si elles sont susceptibles d'être appelées depuis un process préemptif. Afin de gérer ce cas, le compilateur vérifie le caractère "thread safe" des méthodes d'appel sur erreur passées à la commande APPELER SUR ERREUR au moment de la compilation et retourne des erreurs si elles ne sont pas compatibles avec l'exécution en mode préemptif.
A noter que cette vérification est possible uniquement lorsque le nom de la méthode est passé en constante et n'est pas calculé, comme décrit ci-dessous :
APPELER SUR ERREUR("myErrMethod1") //sera vérifiée par le compilateur
APPELER SUR ERREUR("myErrMethod"+Chaine($vNum)) //ne sera pas vérifiée par le compilateur
De plus, à compter de 4D v15 R5, si une méthode projet d'appel sur erreur ne peut pas être appelée à l'exécution (à la suite d'un problème lié au mode préemptif ou pour toute raison, comme par exemple "méthode non trouvée"), une nouvelle erreur est générée : -10532 "Impossible d'ouvrir la méthode d'appel sur erreur 'nomMéthode'".
Un process peut déréférencer un pointeur pour accéder à la valeur d'une autre variable process uniquement si les deux process sont coopératifs ; sinon, 4D retournera une erreur.
Exemples avec les méthodes suivantes :
Méthode 1 :
myVar:=42
$pid:=Nouveau process("Method2";0;"process name";->myVar)
Méthode 2 :
$value:=$1->
Si le process exécutant Méthode 1 ou le process exécutant Méthode 2 est préemptif, l'expression "$value:=$1->" provoquera une erreur d'exécution.
L'utilisation des paramètres de type RefDoc (référence de document ouvert, utilisée ou retournée par les commandes Ouvrir document, Creer document, Ajouter a document, FERMER DOCUMENT, RECEVOIR PAQUET, ENVOYER PAQUET) est limitée aux contextes suivants :
Pour plus d'informations sur la référence RefDoc, veuillez vous reporter à la section RefDoc : numéro de référence de document.
Dans certains cas, il se peut que vous préfériez que la vérification de "thread-safety" des commandes ne s'applique qu'à certaines parties du code, comme par exemple lorsqu'il contient des commandes thread-unsafe qui ne sont jamais appelées.
Pour ce faire, entourez le code à exclure de la vérification thread safety de la commande à l'aide des directives spécifiques %T- et %T+ dans les commentaires. Le commentaire //%T- désactive la vérification thread safety et le commentaire //%T+ la réactive :
// %T- pour désactiver la vérification thread safety
// Placez ici le code contenant les commandes à exclure de la vérification thread safety
$w:=Creer fenetre(10;10;100;100) //par example
// %T+ pour réactiver la vérification thread safety pour le reste de la méthode
Bien entendu, le développeur 4D s'assure que le mode préemptif du code est compatible avec les directives de désactivation et de réactivation. Les erreurs d'exécution seront générées si le code thread-unsafe est exécuté dans un thread préemptif.
Produit : 4D
Thème : Process
Nom intl. : Preemptive 4D processes
Créé : 4D v15 R5
4D - Langage ( 4D v20)
4D - Langage ( 4D v20.1)
4D - Langage ( 4D v20.2)
4D - Langage ( 4D v20.3)
4D - Langage ( 4D v20.4)
4D - Langage ( 4D v20.5)
4D - Langage ( 4D v20.6)