Skip to main content

Utiliser des variables locales de tâche

Les variables locales de tâche sont cohérentes avec le cycle. Ils ne sont écrits que par une tâche définie dans un cycle de tâche, tandis que toutes les autres tâches n'y ont qu'un accès en lecture. Il est pris en compte que les tâches peuvent être interrompues par d'autres tâches ou peuvent s'exécuter en même temps. La cohérence du cycle s'applique également surtout si l'application tourne sur un système avec un processeur multicœur.

L'utilisation de listes de variables globales locales à la tâche est donc un moyen d'obtenir automatiquement la synchronisation (par le compilateur) lorsque plusieurs tâches modifient les mêmes variables. Ce n'est pas le cas lors de l'utilisation de GVL normaux. Plusieurs tâches peuvent écrire simultanément dans des variables GVL normales au cours d'un cycle.

Veuillez noter, cependant, que la synchronisation des variables locales de tâche est relativement longue et gourmande en mémoire et n'est pas le moyen approprié dans toutes les applications. Voir ci-dessous pour des informations techniques plus détaillées et des conseils sur les meilleures pratiques pour vous aider à décider.

Dans le CODESYS projet, le _cds_icon_gvl_tasklocal.png Liste de variables globales (tasklocal) L'objet est disponible pour définir les variables tasklocal. Syntaxiquement, il correspond à un GVL normal, mais contient également les informations de la tâche qui a accès en écriture aux variables. Ensuite, toutes les variables d'un tel GVL ne sont pas modifiées par une autre tâche au cours d'un cycle d'une tâche.

Astuce

Les variables Tasklocal sont des variables complexes dont la valeur ne peut pas être modifiée en mode en ligne à l'aide de l'outil Écrire des valeurs commande.

Dans la section suivante, vous trouverez un exemple simple qui montre le principe et la fonctionnalité des variables locales de tâche : Il existe un programme d'écriture et un programme de lecture. Les programmes s'exécutent dans différentes tâches, mais accèdent aux mêmes données qui se trouvent dans une liste de variables globales locales de tâche afin qu'elles soient traitées de manière cohérente.

Fonctionnalité illustrée dans un exemple

Vous trouverez ci-dessous des instructions pour reprogrammer cet exemple d'application.

Exemple 14. exemple de demande
(* task-local GVL, object name: "Tasklocals" *)
VAR_GLOBAL
        g_diaData : ARRAY [0..99] OF DINT;
END_VAR

PROGRAM ReadData
VAR
        diIndex : DINT;
        bTest : BOOL;
        diValue : DINT;
END_VAR
bTest := TRUE;
diValue := TaskLocals.g_diaData[0];
FOR diIndex := 0 TO 99 DO
    bTest := bTest AND (diValue = Tasklocals.g_diaData[diIndex]);
END_FOR

PROGRAM WriteData
VAR
        diIndex : DINT;
        diCounter : DINT;
END_VAR
diCounter := diCounter + 1;
FOR diIndex := 0 TO 99 DO
        Tasklocals.g_diaData[diIndex] := diCounter;
END_FOR


Les programmes WriteData et Lire les données sont appelés par différentes tâches.

Au programme WriteData devient le tableau g_diaData remplie de valeurs. Le programme ReadData teste si les valeurs du tableau sont comme prévu. Si c'est le cas, la variable renvoie bTest par conséquent TRUE.

Les données du tableau testées concernent la variable g_diaData dans l'objet Tasklocals du genre Globale Variablenliste (tasklokal) déclaré. Cela synchronise l'accès aux données dans le compilateur et la cohérence des données est garantie, même si les programmes d'accès sont appelés à partir de différentes tâches. Dans l'exemple de programme, cela signifie spécifiquement que la variable test au programme ReadData toujours TRUE est.

Si la variable g_diaData n'ont été déclarées que comme une liste de variables globales dans cet exemple, le test , c'est-à-dire la variable test au programme ReadData, plus souvent FALSE livrer. Parce que dans ce cas, l'une des deux tâches du FOR-La boucle peut être interrompue par l'autre tâche, ou les deux tâches peuvent s'exécuter en même temps (contrôleurs multicœurs). Ainsi, les valeurs pourraient être modifiées par l'écrivain pendant que le lecteur lit la liste.

Restrictions de déclaration

Important

Une modification en ligne de l'application n'est pas possible après que des modifications ont été apportées aux déclarations dans la liste des variables locales de tâche.

Notez ce qui suit lors de la déclaration d'une liste globale de variables locales de tâche :

  • N'attribuez pas d'adresses directes via une déclaration AT.

  • Ne mappez pas sur les variables de tâche locales dans la configuration de l'automate.

  • Ne déclarez pas les pointeurs.

  • Ne déclarez pas les références.

  • N'instanciez pas les blocs fonctionnels.

  • Ne déclarez pas de variables locales à la tâche en même temps PERSISTENT et RETAIN.

Un accès en écriture dans une tâche sans autorisation d'écriture est signalé comme une erreur par le compilateur. Cependant, il n'est pas possible de déterminer tous les endroits où les droits d'écriture sont violés. Le compilateur peut uniquement affecter des appels statiques à une tâche. Cependant, l'appel d'un bloc fonction via un pointeur ou une interface n'est pas affecté à une tâche, par exemple. Cela signifie que les accès en écriture n'y sont pas non plus enregistrés. De plus, les pointeurs peuvent pointer vers des variables locales de tâche. De cette façon, les données peuvent être manipulées dans une tâche de lecture. Dans ce cas, aucune erreur d'exécution n'est émise non plus. Cependant, les valeurs modifiées lors de l'accès via des pointeurs ne sont pas recopiées dans la référence commune de la variable.

Propriétés des variables globales locales à la tâche et comportement possible

Les variables sont dans la liste pour chaque tâche à une adresse différente. Cela signifie pour l'accès en lecture : ADR(variable name) renvoie une adresse différente dans chaque tâche.

Le mécanisme de synchronisation garantit ce qui suit :

  • cohérence du cycle

  • Libération des états de verrouillage : A aucun moment une tâche n'attend une action d'une autre tâche.

Cependant, cette méthode ne peut pas être utilisée pour déterminer un instant auquel une tâche de lecture recevra définitivement une copie de la tâche d'écriture. En principe, les copies peuvent diverger. Dans l'exemple ci-dessus, on ne peut pas supposer que chaque copie écrite sera éditée une fois par le lecteur. Par exemple, la tâche de lecture peut traiter le même tableau pendant plusieurs cycles, ou le contenu du tableau peut "sauter" une ou plusieurs valeurs entre deux cycles. Les deux peuvent se produire et doivent être pris en compte.

La tâche d'écriture peut être maintenue pendant un cycle entre deux accès à la référence commune par chaque tâche de lecture. Cela signifie si n des tâches de lecture existent, la tâche d'écriture n Les cycles sont retardés jusqu'à la prochaine mise à jour de la référence partagée.

Une tâche de lecture peut être empêchée d'obtenir une copie lue à chaque cycle par la tâche d'écriture. Il n'est donc pas possible de spécifier un nombre maximum de cycles après lequel une tâche de lecture recevra définitivement une copie.

En particulier, cela peut devenir problématique lorsque des tâches très lentes sont impliquées. En supposant qu'une tâche ne s'exécute que toutes les heures et ne puisse pas accéder aux variables locales de la tâche, la tâche fonctionne avec une très ancienne copie de la liste. Il peut donc être judicieux d'insérer un horodatage dans les variables locales de la tâche, que les tâches de lecture peuvent utiliser pour au moins déterminer si la liste est à jour. Vous pouvez ajouter un horodatage comme suit : Ajoutez une variable de type à la liste des variables locales de la tâche LTIME et dans la tâche d'écriture, par exemple, le code suivant : tasklocal.g_timestamp := LTIME();.

les meilleures pratiques

Les variables locales de tâche sont conçues pour le cas d'utilisation "un seul écrivain - plusieurs lecteurs". Lors de l'implémentation de code qui sera appelé par différentes tâches, l'utilisation de variables locales de tâche est très utile. C'est par exemple le cas de l'exemple d'application décrit ci-dessus appTasklocal le cas où il est étendu par plusieurs tâches de lecture qui accèdent toutes au même tableau et utilisent les mêmes fonctions.

Les variables locales de tâche sont particulièrement utiles sur les systèmes dotés de processeurs multicœurs. Vous ne pouvez pas synchroniser les tâches par priorité sur ces systèmes. Ensuite, le besoin d'autres mécanismes de synchronisation se fait sentir.

N'utilisez pas de variables locales de tâche si une tâche de lecture doit toujours travailler sur la dernière copie de la variable. Les variables de tâche locales ne conviennent pas pour cela.

Un problème similaire est le problème "producteur - consommateur". C'est le cas lorsqu'une tâche produit des données et qu'une seconde tâche les traite. Avec cette constellation, préférez un autre type de synchronisation. Par exemple, le producteur pourrait utiliser un indicateur pour indiquer qu'une nouvelle date est disponible. Le consommateur peut utiliser un deuxième indicateur pour indiquer qu'il a traité ses données et qu'il attend maintenant une nouvelle entrée. Les deux peuvent travailler sur les mêmes données. Il n'y a pas de surcharge pour la copie cyclique des données et le consommateur ne perd aucune donnée générée par le producteur.

surveillance

Lors de l'exécution, il existe plusieurs copies, éventuellement différentes, de la liste des variables locales de la tâche en mémoire. Cependant, toutes les valeurs ne peuvent pas être affichées lors de la surveillance d'une position. Pour cette raison, les valeurs de la référence commune sont affichées pour une variable locale de tâche dans la surveillance en ligne, dans la liste de surveillance et dans la visualisation.

Si vous définissez un point d'arrêt, les données de la tâche qui a atteint le point d'arrêt et qui a été par conséquent arrêtée sont affichées. Pendant ce temps, les autres tâches continuent de s'exécuter. Dans certaines circonstances, la copie commune peut être modifiée. Dans le cadre de la tâche arrêtée, cependant, les valeurs restent inchangées et sont affichées comme telles. Vous devez en être conscient.

Contexte : Mise en œuvre technique

Pour une liste de variables locales de tâche, le compilateur crée une copie pour chaque tâche et une copie de référence commune pour toutes les tâches. Une structure est créée qui contient les mêmes variables que la liste des variables locales de tâche. Un tableau avec cette structure est également créé, avec une dimension de tableau créée pour chaque tâche. Un élément du tableau est ainsi indexé pour chaque tâche. Si une variable de la liste est maintenant accédée dans le code, la copie locale de la liste de la tâche est en fait accédée. De plus, il est déterminé dans quelle tâche le bloc est en cours d'exécution et l'accès est indexé en conséquence.

Par exemple, la ligne de code diValue := TaskLocals.g_diaData[0]; remplacé à partir de l'exemple ci-dessus :

diValue := __TaskLocalVarsArray[__CURRENTTASK.TaskIndex].__g_diarr[0];

__CURRENTTASK est un opérateur qui ab CODESYS La V3.5 SP13 est disponible pour déterminer rapidement l'index de la tâche en cours.

Lors de l'exécution, le contenu de la liste locale des tâches est copié dans la référence commune à la fin de la tâche d'écriture. Dans le cas d'une tâche de lecture, le contenu de la référence commune est copié dans la copie locale de la tâche au début. Il y a donc n+1 copies de la liste pour n tâches : Une liste sert de référence commune et en plus chaque tâche a sa propre copie de la liste.

Un planificateur contrôle l'exécution en temps voulu de plusieurs tâches et donc la commutation de tâche. La stratégie suivie par l'ordonnanceur pour contrôler l'allocation du temps d'exécution vise à éviter de bloquer une tâche. Le mécanisme de synchronisation est donc optimisé pour les propriétés des variables locales de tâche afin que les états bloquants (états verrouillés) soient évités et qu'une tâche n'attende jamais l'action d'une autre tâche.

stratégie de synchronisation :

  • Tant que la tâche d'écriture réécrit une copie dans la référence partagée, aucune des tâches de lecture n'obtient de copie.

  • Tant qu'une tâche de lecture récupère une copie de la référence partagée, la tâche d'écriture ne réécrit pas de copie.

Instructions pour créer l'exemple d'application décrit ci-dessus

Objectif : vous souhaitez démarrer avec un programme ReadData accéder aux mêmes données auxquelles accède un programme WriteData à écrire. Les deux programmes doivent s'exécuter dans des tâches différentes. Vous fournissez les données dans une liste de variables locales à la tâche afin qu'elles soient automatiquement traitées de manière cohérente.

Prérequis : Un projet standard est fraîchement créé et ouvert sous l'éditeur.

  1. Renommez l'application de Application dans appTasklocal environ.

  2. Ajouter ci-dessous appTasklocal un programme en ST par son nom ReadData ajoutée.

  3. Ajouter ci-dessous appTasklocal un autre programme dans ST par nom WriteData ajoutée.

  4. Nommez la tâche par défaut MainTask sous l'objet Taskkonfiguration dans Read environ.

  5. Ajouter dans le dialogue configuration la tâche Read via le bouton Ajouter un appel appeler le programme ReadData ajoutée.

  6. Coller sous l'objet configuration des tâches ajouté une autre tâche nommée avec Write et ajoutez l'appel de programme à cette tâche Write ajoutée.

    Il y a maintenant deux tâches dans la configuration des tâches Write et Readqui les programmes WriteData respectivement ReadData appeler.

  7. Sélectionnez l'application appTasklocal et ajouter un objet de type Liste des variables globales (tâche locale) ajoutée.

    Le dialogue Ajouter une liste de variables globales (tâche-locale). s'ouvre.

  8. Entrez comme nom Tasklocals un.

  9. Choisissez dans la liste déroulante Tâche avec accès en écriture la tâche Write.

    _cds_img_tasklocal_objekcts.png

    La structure d'objet pour l'utilisation des variables de tâche locales dans une application est terminée. Vous pouvez maintenant coder les objets comme indiqué ci-dessus dans la description de l'exemple.