Multi-task data access synchronization in the PLC
When one set of data is accessed by multiple tasks, the tasks may access the same data simultaneously, depending on the task/real-time configuration. If the data is written by at least one of the tasks, the data may have an inconsistent state during or after a change. To prevent this, all concurrent accesses must be synchronized so that only one task can access the shared data at a time.
These concurrent accesses from several tasks that require synchronization include the following cases, for example:
- direct access to global or other non-temporary variables, for example using operators
- indirect access to global or other non-temporary variables, for example within functions, methods, or other POU calls (especially if a function block instance is globally instantiated)
In brief: If one set of data is accessed by several tasks and the data is written by at least one of these accesses, all read and write accesses must be synchronized. This applies regardless of whether the tasks are run on a single or multiple CPU cores.
WARNING | |
Risk of injury due to unforeseen axis movement If concurrent accesses are not synchronized, there is a risk that the data records will be inconsistent or invalid. Depending on how the data is used in the further course of the program, this can result in incorrect program behavior, undesired axis movement, or even a sudden program standstill. Damage to equipment and workpieces may occur, or people's health and lives may be endangered, depending on the controlled system.
|
Synchronization options
The following options are available for synchronizing accesses:
- Mutex procedure (TestAndSet, FB_IecCriticalSection) for securing critical sections
- The number of critical sections must always be kept as small as possible.
- The critical sections must be kept short.
- For comparatively short critical sections, the use of FB_IecCriticalSection is usually recommended.
- For comparatively long critical sections, the use of TestAndSet is usually recommended.
- Data exchange via the PLC process image
- This variant is only possible and recommended if only one task has write access to the same data.
- The possible data volume is limited due to necessary internal copy actions. For further information, please refer to the description under “Data exchange via the PLC process image”.
- Data exchange via synchronized buffers
- This variant is only possible if only one task has write access to the same data.
- This is a user-specific implementation for which there are various options.
- Access to the individual buffers must be secured, for example with TestAndSet().
- The possible data volume is limited due to executed copy actions. For further information, please refer to the description under “Data exchange via synchronized buffers”.
Synchronization also in the case of atomic access
The necessity for synchronization normally also applies even if a single access to a variable (e.g. writing an integer) could be described as atomic, i.e. uninterruptible.
Because the property of the atomic access depends among other things on the processor architecture used, every access should be regarded as non-atomic for simplicity's sake and for safety.
It should also be noted that even supposedly safe accesses almost always turn out to be unsafe when considered more closely. This is explained below with the help of two example scenarios:
- As a rule, more than one atomic access is necessary for the desired function expression (e.g. read, change, write). If such a multi-part function expression exists in several tasks, the simultaneous execution on several tasks can lead to a different result than the sequential execution of the expressions.
- Example: A global counter variable (initialized with 0) is to be incremented by 1 (from two tasks) (
nGlobal := nGlobal + 1;
). If the incrementation is executed at the same time,0 + 1 = 1
is calculated both times and the resulting value of the global variable is 1, although the value 2 was intended. - Several read accesses at different times within a task execution can deliver different variable values.
- Example: A global variable is written from a task. Its value was previously 50 and is now written to 0 (
nGlobal := 0;
). In a different task context the value of the global variable is queried (IF nGlobal>10 AND nGlobal<20 THEN
). The query consists of two read accesses. If the above write access takes place from the other task between these read accesses, then the condition is fulfilled, even though the global variable did not have a value of between 10 and 20 at any point in time.
Additional Notes
- System operators such as ADD, SIZEOF or __NEW can be called by several tasks simultaneously. This statement only refers to the operator used. If data is accessed during the calls, which in turn is used by several tasks, these data accesses must be synchronized accordingly.
- A function block instance that uses ADS internally may not be used in different tasks. If the instance is nevertheless called from another task, the error ADSERR_DEVICE_INVALIDCONTEXT=0x709=1801 is issued.
- Due to the execution on the stack, the use of the STRING functions (Tc2_Standard library) in different tasks is not critical in TwinCAT 3 (in TwinCAT 2 the STRING functions are not safe by default for task changes).
- Also note the possibilities of the compiler extension (documentation TE1200 TC3 PLC Static Analysis), which provides rules on the topic of “concurrency/competing accesses”. This should be seen as a tool to identify potential synchronization requirements.