Multiple Tasks
Themenpunkte:
Details zur Absicherung von konkurrierendem Zugriff sind im Kapitel Multitask-Datenzugriffs-Synchronisation in der SPS beschrieben.
Konkurrierende Zugriffe auf Speicherbereiche vermeiden
Konkurrierende Zugriffe auf Speicherbereiche sollten Sie vermeiden. Ein konkurrierender Zugriff auf Speicherbereiche tritt beispielsweise auf, wenn Variablen von mehr als einem Task gelesen und/oder geschrieben werden, wobei mindestens ein schreibender Zugriff vorliegt.
Hinweis | |
Inkonsistente Variablenwerte Wird aus mehreren Taskkontexten beispielsweise auf eine globale Variable zugegriffen und erfolgt mindestens ein Zugriff auch schreibend, kann der Variablenwert mit großer Wahrscheinlichkeit inkonsistent werden. Ein inkonsistenter Variablenwert kann schwerwiegende Folgen auf den Programmablauf haben und einen Stopp der SPS bewirken. |
Static Analysis:
Überprüfen mit Hilfe der folgenden Static Analysis Regeln:
Die Regel SA0006 ist auch in der lizenzfreien Variante Static Analysis Light enthalten.
Negatives Beispiel:
GVL_Sample:
VAR_GLOBAL
nTestOutput AT%Q* : WORD; // Test output to be allocated
nGlobalCounter : UDINT;
nLastErrorID : UDINT;
END_VAR
Programm Sample_neg_task_M, ausgeführt in Task M:
PROGRAM Sample_neg_task_M
VAR
nLocalTaskM : WORD;
fbLocalTaskM : FB_Test;
END_VAR
GVL_Sample.nTestOutput := nLocalTaskM; // NON COMPLIANT: Task N reads variable being written by Task M whereas the accesses are not synchronized.
GVL_Sample.nGlobalCounter := GVL_Sample.nGlobalCounter + 1; // NON COMPLIANT: Task M & Task N write to GVL_Sample.nGlobalCounter
GVL_Sample.nLastErrorID := fbLocalTaskM.nErrorID; // NON COMPLIANT: Task M & Task N write to GVL_Sample.nLastErrorID
Programm Sample_neg_task_N, ausgeführt in Task N:
PROGRAM Sample_neg_task_N
VAR
nLocalTaskN : DWORD;
fbLocalTaskN : FB_Test;
END_VAR
nLocalTaskN := GVL_Sample.nTestOutput; // NON COMPLIANT: Task N reads variable being written by Task M whereas the accesses are not synchronized.
GVL_Sample.nGlobalCounter := 0; // NON COMPLIANT: Task M & Task N write to GVL_Sample.nGlobalCounter
GVL_Sample.nLastErrorID := fbLocalTaskN.nErrorID; // NON COMPLIANT: Task M & Task N write to GVL_Sample.nLastErrorID
Positives Beispiel:
GVL_Sample:
VAR_GLOBAL
nTestOutput AT%Q* : WORD; // Test output to be allocated
nGlobalCounter : UDINT;
nLastErrorID_TaskM : UDINT; // only used in Task M
nLastErrorID_TaskN : UDINT; // only used in Task N
END_VAR
Programm Sample_pos_task_M, ausgeführt in Task M:
PROGRAM Sample_pos_task_M
VAR
nLocalTaskM : WORD;
fbLocalTaskM : FB_Test;
END_VAR
GVL_Sample.nLastErrorID_TaskM := fbLocalTaskN.nErrorID; // writes data that is declared for task M and only used in task M
IF (* special condition to synchronize access - see InfoSys chapter 'multitask data access' *) THEN
GVL_Sample.nTestOutput := nLocalTaskM;
GVL_Sample.nGlobalCounter := GVL_Sample.nGlobalCounter + 1;
END_IF
Programm Sample_pos_task_N, ausgeführt in Task N:
PROGRAM Sample_pos_task_N
VAR
nLocalTaskN : DWORD;
fbLocalTaskN : FB_Test;
END_VAR
GVL_Sample.nLastErrorID_TaskN := fbLocalTaskN.nErrorID; // writes data that is declared for task N and only used in task N
IF (* special condition to synchronize access - see InfoSys chapter 'multitask data access' *) THEN
nLocalTaskN := GVL_Sample.nTestOutput;
GVL_Sample.nGlobalCounter := 0;
END_IF
Konkurrierende Zugriffe auf Funktionsbausteine vermeiden
Konkurrierende Zugriffe auf Funktionsbausteine sollten Sie vermeiden.
Ein Zugriff aus mehreren Taskkontexten auf einen Funktionsbaustein ist nicht erlaubt. Das betrifft sowohl den Aufruf des Rumpfes als auch von Methoden oder Properties. Der interne Ablauf kann mit großer Wahrscheinlichkeit zu inkonsistenten Variablenwerten führen. Die Auswirkungen sind wiederum schwerwiegende Folgen auf den Programmablauf oder ein sofortiger Stopp der SPS.
In wenigen Ausnahmen erlaubt die Definition eines Funktionsbausteines einen Zugriff aus mehreren Taskkontexten. Sollte ein Funktionsbaustein für diesen Anwendungsfall konzipiert und entwickelt sein, so ist dies explizit dokumentiert. In allen anderen Fällen ist eine globale Instanziierung und Verwendung aus mehreren Taskkontexten nicht erlaubt.
Globale Variablen mit Bedacht verwenden
Um konkurrierenden Zugriffen vorzubeugen und die Datenkapselung zu unterstützen, möglichst auf globale Instanziierungen verzichten.
Ebenso sollten Sie innerhalb von Funktionsbausteinen möglichst auf die Verwendung von vorhandenen globalen Variablen verzichten. Notwendige Daten weisen Sie über Eingangsparameter zu.