Skip to main content

Usar variables locales de tareas

Las variables locales de tareas son coherentes con el ciclo. Solo las escribe una tarea definida en un ciclo de tareas, mientras que todas las demás tareas solo tienen acceso de lectura. Se tiene en cuenta que las tareas pueden ser interrumpidas por otras tareas o pueden ejecutarse al mismo tiempo. La coherencia de ciclo también se aplica sobre todo si la aplicación se ejecuta en un sistema con un procesador multinúcleo.

El uso de listas de variables globales locales de tareas es, por lo tanto, una forma de obtener sincronización automáticamente (por parte del compilador) cuando varias tareas editan las mismas variables. Este no es el caso cuando se utilizan GVL normales. Varias tareas pueden escribir simultáneamente en variables GVL normales durante un ciclo.

Tenga en cuenta, sin embargo, que la sincronización de las variables locales de la tarea requiere relativamente mucho tiempo y memoria y no es el medio adecuado en todas las aplicaciones. Consulte a continuación para obtener información técnica más detallada y consejos de mejores prácticas para ayudarlo a decidir.

En el CODESYS proyecto, el _cds_icon_gvl_tasklocal.png Lista de variables globales (tasklocal) El objeto está disponible para definir variables locales de tareas. Sintácticamente corresponde a un GVL normal, pero también contiene la información de la tarea que tiene acceso de escritura a las variables. Entonces, ninguna otra tarea cambia todas las variables en dicha GVL durante el ciclo de una tarea.

Sugerencia

Las variables tasklocal son variables complejas cuyo valor no se puede cambiar en modo en línea utilizando el Escribir valores dominio.

En la siguiente sección encontrará un ejemplo simple que muestra el principio y la funcionalidad de las variables locales de tareas: hay un programa de escritura y uno de lectura. Los programas se ejecutan en diferentes tareas, pero acceden a los mismos datos que se encuentran en una lista de variables globales locales de tareas para que se procesen de manera consistente en el ciclo.

Funcionalidad mostrada en un ejemplo

Las instrucciones para reprogramar esta aplicación de muestra se pueden encontrar a continuación.

ejemplo 14. aplicación de muestra
(* 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


Los programas Escribir datos y Leer datos son llamados por diferentes tareas.

en programa WriteData se convierte en la matriz g_diaData llena de valores. El programa ReadData prueba si los valores de la matriz son los esperados. Si este es el caso, la variable devuelve bTest como resultado TRUE.

Los datos de matriz que se están probando son sobre la variable g_diaData en el objeto Tasklocals del tipo Globale Variablenliste (tasklokal) declarado. Esto sincroniza el acceso a los datos en el compilador y se garantiza que los datos serán coherentes con el ciclo, incluso si los programas de acceso se llaman desde diferentes tareas. En el programa de muestra esto significa específicamente que la variable test en programa ReadData siempre TRUE es.

Si la variable g_diaData solo se declaró como una lista de variables globales en este ejemplo, la prueba, es decir, la variable test en programa ReadData, más a menudo FALSE entregar. Porque en este caso una de las dos tareas en el FOR-El bucle puede ser interrumpido por la otra tarea, o ambas tareas pueden ejecutarse al mismo tiempo (controladores multinúcleo). Y así, el escritor podría cambiar los valores mientras el lector lee la lista.

Restricciones de declaración

Importante

Después de realizar cambios en las declaraciones en la lista de variables locales de la tarea, no es posible un cambio en línea de la aplicación.

Tenga en cuenta lo siguiente cuando declare una lista de variables locales de tareas globales:

  • No asigne direcciones directas a través de una declaración AT.

  • No asigne variables de tareas locales en la configuración del PLC.

  • No declarar punteros.

  • No declarar referencias.

  • No cree instancias de bloques de funciones.

  • No declarar variables locales de tareas al mismo tiempo PERSISTENT y RETAIN.

El compilador informa como un error un acceso de escritura en una tarea sin permiso de escritura. Sin embargo, no es posible determinar todos los lugares donde se violan los derechos de escritura. El compilador solo puede asignar llamadas estáticas a una tarea. Sin embargo, la llamada de un bloque de funciones a través de un puntero o una interfaz no se asigna a una tarea, por ejemplo. Esto significa que los accesos de escritura tampoco se registran allí. Además, los punteros pueden apuntar a variables locales de tareas. De esta manera, los datos pueden ser manipulados en una tarea de lectura. En este caso, tampoco se emite ningún error de tiempo de ejecución. Sin embargo, los valores cambiados al acceder a través de punteros no se vuelven a copiar en la referencia común de las variables.

Propiedades de las variables globales locales de tareas y posible comportamiento

Las variables están en la lista para cada tarea en una dirección diferente. Eso significa para el acceso de lectura: ADR(variable name) devuelve una dirección diferente en cada tarea.

El mecanismo de sincronización garantiza lo siguiente:

  • consistencia del ciclo

  • Libertad de estados de bloqueo: en ningún momento una tarea espera una acción de otra tarea.

Sin embargo, este método no se puede utilizar para determinar un punto en el tiempo en el que una tarea de lectura definitivamente recibirá una copia de la tarea de escritura. En principio, las copias pueden divergir. En el ejemplo anterior, no se puede suponer que cada copia escrita será editada una vez por el lector. Por ejemplo, la tarea de lectura puede procesar la misma matriz durante varios ciclos, o el contenido de la matriz puede "saltar" uno o más valores entre dos ciclos. Ambas pueden ocurrir y deben ser tenidas en cuenta.

La tarea de escritura se puede detener durante un ciclo entre dos accesos a la referencia común por cada tarea de lectura. Eso significa que si n existen tareas de lectura, la tarea de escritura n Los ciclos se retrasan hasta la próxima actualización de la referencia compartida.

La tarea de escritura puede evitar que una tarea de lectura obtenga una copia leída en cada ciclo. Por lo tanto, no es posible especificar un número máximo de ciclos después de los cuales una tarea de lectura definitivamente recibirá una copia.

En particular, esto puede volverse problemático cuando se trata de tareas de ejecución muy lenta. Suponiendo que una tarea solo se ejecuta cada hora y luego no puede acceder a las variables locales de la tarea, entonces la tarea está trabajando con una copia muy antigua de la lista. Por lo tanto, puede tener sentido insertar una marca de tiempo en las variables locales de la tarea, que las tareas de lectura pueden usar para al menos determinar si la lista está actualizada. Puede agregar una marca de tiempo de la siguiente manera: Agregar una variable de tipo a la lista de variables locales de tareas LTIME y en la tarea de escritura, por ejemplo, el siguiente código: tasklocal.g_timestamp := LTIME();.

mejores prácticas

Las variables locales de tareas están diseñadas para el caso de uso "escritor único - lectores múltiples". Cuando se implementa código que será llamado por diferentes tareas, el uso de variables locales de tareas es de gran beneficio. Por ejemplo, este es el caso con la aplicación de muestra descrita anteriormente appTasklocal el caso cuando se extiende por varias tareas de lectura que acceden a la misma matriz y usan las mismas funciones.

Las variables locales de tareas son especialmente útiles en sistemas con procesadores multinúcleo. No puede sincronizar tareas por prioridad en estos sistemas. Entonces surge la necesidad de otros mecanismos de sincronización.

No utilice variables locales de tarea si una tarea de lectura siempre debe funcionar en la última copia de la variable. Las variables de tareas locales no son adecuadas para esto.

Un problema similar es el problema "productor - consumidor". Este es el caso cuando una tarea produce datos y una segunda tarea los procesa. Con esta constelación, prefiera un tipo diferente de sincronización. Por ejemplo, el productor podría usar una bandera para indicar que hay una nueva fecha disponible. El consumidor puede usar una segunda bandera para indicar que ha procesado sus datos y ahora está esperando una nueva entrada. Ambos pueden trabajar con los mismos datos. No hay sobrecarga por la copia cíclica de los datos y el consumidor no pierde ningún dato generado por el productor.

supervisión

En tiempo de ejecución, hay varias copias, posiblemente diferentes, de la lista de variables locales de la tarea en la memoria. Sin embargo, no todos los valores se pueden mostrar al monitorear una posición. Por esta razón, los valores de la referencia común se muestran para una variable local de tarea en el monitoreo en línea, en la lista de monitoreo y en la visualización.

Si establece un punto de interrupción, se muestran los datos de la tarea que alcanzó el punto de interrupción y, en consecuencia, se detuvo. Mientras tanto, las otras tareas continúan ejecutándose. Bajo ciertas circunstancias, la copia común se puede cambiar. Sin embargo, en el contexto de la tarea detenida, los valores permanecen sin cambios y se muestran como tales. Debes ser consciente de esto.

Antecedentes: implementación técnica

Para una lista de variables locales de tareas, el compilador crea una copia para cada tarea y una copia de referencia común para todas las tareas. Se crea una estructura que contiene las mismas variables que la lista de variables locales de tareas. También se crea una matriz con esta estructura, y se crea una dimensión de matriz para cada tarea. Por lo tanto, se indexa un elemento de matriz para cada tarea. Si ahora se accede a una variable de la lista en el código, en realidad se accede a la copia local de la tarea de la lista. Además, se determina en qué tarea se está ejecutando actualmente el bloque y el acceso se indexa en consecuencia.

Por ejemplo, la línea de código diValue := TaskLocals.g_diaData[0]; reemplazado del ejemplo anterior:

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

__CURRENTTASK es un operador que ab CODESYS V3.5 SP13 está disponible para determinar rápidamente el índice de tareas actual.

En tiempo de ejecución, el contenido de la lista local de tareas se copia en la referencia común al final de la tarea de escritura. En el caso de una tarea de lectura, el contenido de la referencia común se copia en la copia local de la tarea al principio. Por lo tanto, hay n+1 copias de la lista para n tareas: una lista sirve como referencia común y, además, cada tarea tiene su propia copia de la lista.

Un programador controla la ejecución oportuna de múltiples tareas y, por lo tanto, el cambio de tareas. La estrategia seguida por el planificador para controlar la asignación del tiempo de ejecución tiene como objetivo evitar el bloqueo de una tarea. Por lo tanto, el mecanismo de sincronización está optimizado para las propiedades de las variables locales de la tarea, de modo que se evitan los estados de bloqueo (estados bloqueados) y una tarea nunca espera la acción de otra tarea.

estrategia de sincronización:

  • Siempre que la tarea de escritura escriba una copia en la referencia compartida, ninguna de las tareas de lectura obtendrá una copia.

  • Siempre que una tarea de lectura obtenga una copia de la referencia compartida, la tarea de escritura no vuelve a escribir una copia.

Instrucciones para crear la aplicación de ejemplo descrita anteriormente

Objetivo: quieres empezar con un programa ReadData acceder a los mismos datos a los que accede un programa WriteData para ser escrito. Los dos programas deben ejecutarse en tareas diferentes. Usted proporciona los datos en una lista de variables locales de la tarea para que se procesen automáticamente de forma coherente con el ciclo.

Requisito: Un proyecto estándar recién creado y abierto en el editor.

  1. Cambiar el nombre de la aplicación de Application en appTasklocal alrededor.

  2. Agrega abajo appTasklocal un programa en ST por nombre ReadData adicional.

  3. Agrega abajo appTasklocal otro programa en ST por nombre WriteData adicional.

  4. Asigne un nombre a la tarea predeterminada MainTask bajo el objeto Taskkonfiguration en Read alrededor.

  5. Añadir en el diálogo configuración la tarea Read a través del botón Agregar llamada llamando al programa ReadData adicional.

  6. Pegar debajo del objeto configuración de tareas agregó otra tarea nombrada con Write y agregue la llamada del programa a esta tarea Write adicional.

    Ahora hay dos tareas en la configuración de tareas Write y Readquien los programas WriteData respectivamente ReadData llamar.

  7. Seleccione la aplicación appTasklocal y agregar un objeto de tipo Lista de variables globales (tarea local) adicional.

    El diálogo Agregar lista de variables globales (tarea local). se abre

  8. Ingresar como nombre Tasklocals una.

  9. Elija de la lista desplegable Tarea con acceso de escritura la tarea Write.

    _cds_img_tasklocal_objekcts.png

    La estructura de objetos para usar variables de tareas locales dentro de una aplicación está completa. Ahora puede codificar los objetos como se muestra arriba en la descripción del ejemplo.