Multiple Tasks

Themenpunkte:

  1. Konkurrierende Zugriffe auf Speicherbereiche vermeiden [++]
  2. Konkurrierende Zugriffe auf Funktionsbausteine vermeiden [++]
  3. Globale Variablen mit Bedacht verwenden [+]

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.