Usa variabili locali dell'attività
Le variabili task-local sono coerenti con il ciclo. Vengono scritti solo da un'attività definita in un ciclo di attività, mentre tutte le altre attività possono solo leggerli. Si tiene conto del fatto che le attività possono essere interrotte da altre attività o possono essere eseguite contemporaneamente. La consistenza del ciclo vale soprattutto se l'applicazione è in esecuzione su un sistema con processore multi-core.
L'uso degli elenchi di variabili globali locali delle attività è quindi un modo per ottenere automaticamente la sincronizzazione (dal compilatore) quando più attività modificano le stesse variabili. Questo non è il caso quando si utilizzano normali GVL. Diverse attività possono scrivere contemporaneamente su normali variabili GVL durante un ciclo.
Si noti, tuttavia, che la sincronizzazione delle variabili locali dell'attività è relativamente dispendiosa in termini di tempo e di memoria e non è il mezzo appropriato in ogni applicazione. Vedi sotto per informazioni tecniche più dettagliate e consigli sulle migliori pratiche per aiutarti a decidere.
Nel CODESYS progetto, il Elenco variabili globali (tasklocal) L'oggetto è disponibile per definire le variabili tasklocal. Sintatticamente corrisponde ad un normale GVL, ma contiene anche le informazioni del task che ha accesso in scrittura alle variabili. Quindi tutte le variabili in tale GVL non vengono modificate da un'altra attività durante il ciclo di un'attività.
Suggerimento
Le variabili tasklocal sono variabili complesse il cui valore non può essere modificato in modalità online utilizzando il file Scrivi valori comando.
Nella prossima sezione troverai un semplice esempio che mostra il principio e la funzionalità delle variabili task-local: C'è un programma di scrittura e di lettura. I programmi vengono eseguiti in attività diverse, ma accedono agli stessi dati che si trovano in un elenco di variabili globali locali dell'attività in modo che vengano elaborati in modo ciclo coerente.
Funzionalità mostrata in un esempio
Di seguito sono riportate le istruzioni per la riprogrammazione di questa applicazione di esempio.
(* 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
I programmi Scrivi dati e Leggi dati sono chiamati da compiti diversi.
In programma WriteData
diventa la matrice g_diaData
pieno di valori. Il programma ReadData
verifica se i valori dell'array sono come previsto. Se questo è il caso, la variabile ritorna bTest
di conseguenza TRUE
.
I dati dell'array in fase di test riguardano la variabile g_diaData
nell'oggetto Tasklocals
del tipo Globale Variablenliste (tasklokal)
dichiarato. Ciò sincronizza l'accesso ai dati nel compilatore e si garantisce che i dati siano coerenti con il ciclo, anche se i programmi di accesso vengono richiamati da task diversi. Nel programma di esempio questo significa specificamente che la variabile test
in programma ReadData
sempre TRUE
è.
Se la variabile g_diaData
è stato dichiarato solo come elenco di variabili globali in questo esempio, il test , ovvero la variabile test
in programma ReadData
, più spesso FALSE
consegnare. Perché in questo caso uno dei due compiti nel file FOR
-Loop può essere interrotto dall'altra attività o entrambe le attività potrebbero essere eseguite contemporaneamente (controller multi-core). E così i valori potrebbero essere modificati da chi scrive mentre il lettore legge la lista.
Restrizioni alla dichiarazione
Importante
Una modifica online dell'applicazione non è possibile dopo che sono state apportate modifiche alle dichiarazioni nell'elenco delle variabili task-local.
Tenere presente quanto segue quando si dichiara un elenco di variabili locali dell'attività globale:
Non assegnare indirizzi diretti tramite una dichiarazione AT.
Non eseguire il mapping alle variabili attività locali nella configurazione del PLC.
Non dichiarare i puntatori.
Non dichiarare riferimenti.
Non istanziare blocchi funzione.
Non dichiarare le variabili locali dell'attività come allo stesso tempo
PERSISTENT
eRETAIN
.
Un accesso in scrittura a un'attività senza autorizzazione di scrittura viene segnalato come errore dal compilatore. Tuttavia, non è possibile determinare tutti i luoghi in cui i diritti di scrittura vengono violati. Il compilatore può assegnare solo chiamate statiche a un'attività. Tuttavia, il richiamo di un blocco funzione tramite un puntatore o un'interfaccia non è assegnato, ad es., a un task. Ciò significa che anche gli accessi in scrittura non vengono registrati lì. Inoltre, i puntatori possono puntare a variabili locali dell'attività. In questo modo, i dati possono essere manipolati in un'attività di lettura. Anche in questo caso non viene emesso alcun errore di runtime. Tuttavia, i valori modificati durante l'accesso tramite puntatori non vengono ricopiati nel riferimento comune delle variabili.
Proprietà delle variabili globali task-local e possibile comportamento
Le variabili sono nell'elenco per ogni attività a un indirizzo diverso. Ciò significa per l'accesso in lettura: ADR(variable name)
restituisce un indirizzo diverso in ogni attività.
Il meccanismo di sincronizzazione garantisce quanto segue:
consistenza del ciclo
Libertà dagli stati di blocco: in nessun momento un'attività attende un'azione da parte di un'altra attività.
Tuttavia, questo metodo non può essere utilizzato per determinare un momento in cui un'attività di lettura riceverà sicuramente una copia dell'attività di scrittura. In linea di principio, le copie possono divergere. Nell'esempio sopra, non si può presumere che ogni copia scritta verrà modificata una volta dal lettore. Ad esempio, l'attività di lettura può elaborare lo stesso array per diversi cicli, oppure il contenuto dell'array può "saltare" uno o più valori tra due cicli. Entrambi possono verificarsi e devono essere presi in considerazione.
L'attività di scrittura può essere sospesa per un ciclo tra due accessi al riferimento comune da parte di ciascuna attività di lettura. Ciò significa se n
le attività di lettura esistono, l'attività di scrittura n
I cicli sono ritardati fino al prossimo aggiornamento del riferimento comune.
È possibile impedire a un'attività di lettura di ottenere una copia di lettura in ogni ciclo dall'attività di scrittura. Non è quindi possibile specificare un numero massimo di cicli dopo i quali un'attività di lettura ne riceverà sicuramente una copia.
In particolare, questo può diventare problematico quando sono coinvolti compiti a esecuzione molto lenta. Supponendo che un'attività venga eseguita solo ogni ora e quindi non possa accedere alle variabili locali dell'attività, l'attività sta lavorando con una copia molto vecchia dell'elenco. Può quindi avere senso inserire un timestamp nelle variabili locali dell'attività, che le attività di lettura possono utilizzare per determinare almeno se l'elenco è aggiornato. È possibile aggiungere un timestamp come segue: Aggiungere una variabile di tipo all'elenco delle variabili locali dell'attività LTIME
e nell'attività di scrittura, ad esempio, il seguente codice: tasklocal.g_timestamp := LTIME();
.
migliori pratiche
Le variabili task-local sono progettate per il caso d'uso "scrittore singolo - lettori multipli". Quando si implementa il codice che verrà chiamato da attività diverse, l'utilizzo di variabili locali dell'attività è di grande vantaggio. Ad esempio, questo è il caso dell'applicazione di esempio sopra descritta appTasklocal
il caso in cui è esteso da più attività di lettura che accedono tutte allo stesso array e utilizzano le stesse funzioni.
Le variabili task-local sono particolarmente utili su sistemi con processori multi-core. Non è possibile sincronizzare le attività in base alla priorità su questi sistemi. Quindi sorge la necessità di altri meccanismi di sincronizzazione.
Non utilizzare le variabili locali dell'attività se un'attività di lettura deve sempre funzionare sull'ultima copia della variabile. Le variabili attività locali non sono adatte a questo.
Un problema simile è il problema "produttore - consumatore". Questo è il caso in cui un'attività produce dati e una seconda attività li elabora. Con questa costellazione, preferisci un diverso tipo di sincronizzazione. Ad esempio, il produttore potrebbe utilizzare un flag per indicare che è disponibile una nuova data. Il consumatore può utilizzare un secondo flag per indicare che ha elaborato i suoi dati ed è ora in attesa di un nuovo input. Entrambi possono lavorare sugli stessi dati. Non vi è alcun sovraccarico per la copia ciclica dei dati e il consumatore non perde alcun dato generato dal produttore.
monitoraggio
In fase di esecuzione, sono presenti in memoria diverse copie, possibilmente diverse, dell'elenco delle variabili locali dell'attività. Tuttavia, non tutti i valori possono essere visualizzati durante il monitoraggio di una posizione. Per questo motivo, i valori del riferimento comune vengono visualizzati per una variabile task-local nel monitoraggio in linea, nell'elenco di monitoraggio e nella visualizzazione.
Se si imposta un punto di interruzione, vengono visualizzati i dati dell'attività che ha raggiunto il punto di interruzione e di conseguenza è stata interrotta. Nel frattempo, le altre attività continuano a essere eseguite. In determinate circostanze, la copia comune può essere modificata. Nel contesto dell'attività interrotta, invece, i valori rimangono invariati e vengono visualizzati come tali. Devi essere consapevole di questo.
Contesto: implementazione tecnica
Per un elenco di variabili locali dell'attività, il compilatore crea una copia per ciascuna attività e una copia di riferimento comune per tutte le attività. Viene creata una struttura che contiene le stesse variabili dell'elenco delle variabili locali dell'attività. Viene creata anche una matrice con questa struttura, con una dimensione della matrice creata per ogni attività. Un elemento dell'array viene quindi indicizzato per ogni attività. Se ora si accede a una variabile dell'elenco nel codice, si accede effettivamente alla copia locale dell'attività dell'elenco. Inoltre, viene determinato in quale attività è attualmente in esecuzione il blocco e l'accesso viene indicizzato di conseguenza.
Ad esempio, la riga di codice diValue := TaskLocals.g_diaData[0];
sostituito dall'esempio sopra:
diValue := __TaskLocalVarsArray[__CURRENTTASK.TaskIndex].__g_diarr[0];
__CURRENTTASK
è un operatore che ab CODESYS V3.5 SP13 è disponibile per determinare rapidamente l'indice dell'attività corrente.
In fase di esecuzione, il contenuto dell'elenco locale delle attività viene copiato nel riferimento comune alla fine dell'attività di scrittura. Nel caso di un'attività di lettura, il contenuto del riferimento comune viene copiato all'inizio nella copia locale dell'attività. Pertanto ci sono n+1 copie dell'elenco per n compiti: un elenco funge da riferimento comune e inoltre ogni compito ha la propria copia dell'elenco.
Uno scheduler controlla l'esecuzione tempestiva di più attività e quindi il cambio di attività. La strategia seguita dallo scheduler per controllare l'allocazione del tempo di esecuzione mira a evitare il blocco di un'attività. Il meccanismo di sincronizzazione è quindi ottimizzato per le proprietà delle variabili locali dell'attività in modo da evitare stati di blocco (stati bloccati) e un'attività non attende mai l'azione di un'altra attività.
strategia di sincronizzazione:
Finché l'attività di scrittura riscrive una copia nel riferimento condiviso, nessuna delle attività di lettura ne riceve una copia.
Finché un'attività di lettura recupera una copia dal riferimento condiviso, l'attività di scrittura non ne riscrive una copia.
Istruzioni per la creazione dell'applicazione di esempio sopra descritta
Obiettivo: vuoi iniziare con un programma ReadData
accedere agli stessi dati a cui accede un programma WriteData
da scrivere. I due programmi dovrebbero essere eseguiti in attività diverse. Fornisci i dati in un elenco di variabili locali dell'attività in modo che vengano elaborati automaticamente in modo coerente.
Presupposto: un progetto standard è stato appena creato e aperto nell'editor.
Rinominare l'applicazione da
Application
inappTasklocal
in giro.Aggiungi di seguito
appTasklocal
un programma in ST per nomeReadData
aggiunto.Aggiungi di seguito
appTasklocal
un altro programma in ST per nomeWriteData
aggiunto.Assegna un nome all'attività predefinita
MainTask
sotto l'oggettoTaskkonfiguration
inRead
in giro.Aggiungi nel dialogo configurazione l'obiettivo
Read
tramite il pulsante Aggiungi chiamata chiamando il programmaReadData
aggiunto.Incolla sotto l'oggetto configurazione dell'attività aggiunto un'altra attività denominata con
Write
e aggiungi la chiamata al programma a questa attivitàWrite
aggiunto.Ora sono presenti due attività nella configurazione delle attività
Write
eRead
chi i programmiWriteData
rispettivamenteReadData
chiamata.Seleziona l'applicazione
appTasklocal
e aggiungi un oggetto di tipo Elenco delle variabili globali (attività locale) aggiunto.Il dialogo Aggiungi un elenco di variabili globali (task-local). si apre.
Inserisci come nome
Tasklocals
uno.Scegli dall'elenco a discesa Attività con accesso in scrittura l'obiettivo
Write
.La struttura dell'oggetto per l'utilizzo delle variabili attività locali all'interno di un'applicazione è completa. Ora puoi codificare gli oggetti come mostrato sopra nella descrizione dell'esempio.