Multiple tasks

Topics:

  1. Avoid concurrent accesses to memory areas [++]
  2. Avoid concurrent accesses to function blocks [++]
  3. Use global variables wisely [+]

Details on protection from concurrent access are described in the chapter Multi-task data access synchronization in the PLC.

Avoid concurrent accesses to memory areas

You should avoid concurrent accesses to memory areas. For example, concurrent access to memory areas occurs when variables are read and/or written by more than one task with at least one write access.

Notice

Inconsistent variable values

For example, if a global variable is accessed from multiple task contexts and at least one access is also write access, the variable value is very likely to become inconsistent. An inconsistent variable value usually has serious consequences on the program flow and can also cause a stop of the PLC.

Static Analysis:

Verify using the following Static Analysis rules:

The rule SA0006 is also included in the license-free variant Static Analysis Light.

Negative sample:

GVL_Sample:

VAR_GLOBAL
    nTestOutput    AT%Q*  : WORD;  // Test output to be allocated
    nGlobalCounter        : UDINT;
    nLastErrorID          : UDINT;
END_VAR

Program Sample_neg_task_M, executed 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

Program Sample_neg_task_N, executed 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

Positive sample:

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

Program Sample_pos_task_M, executed 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

Program Sample_pos_task_N, executed 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

Avoid concurrent accesses to function blocks

You should avoid concurrent accesses to function blocks.

Access from several task contexts to one function block is not allowed. This concerns both the call of the body and of methods or properties. The internal process is very likely to result in inconsistent variable values. The effects are again serious consequences on the program sequence or an immediate stop of the PLC.

In a few exceptions, the definition of a function block allows access from several task contexts. If a function block is designed and developed for this use case, this is explicitly documented. In all other cases, global instantiation and use from several task contexts is not allowed.

Use global variables wisely

To prevent concurrent access and to support data encapsulation, avoid global instantiations if possible.

Likewise, you should avoid using existing global variables within function blocks if possible. You assign necessary data via input parameters.