Operator: __XADD
Der Multicore-Operator ist eine Erweiterung der Norm IEC 61131-3.
Der Operator kann zur Realisierung eines atomaren Zählers verwendet werden. Wenn eine Integer-Variable mit einer normalen Addition, zum Beispiel iTest := iTest + 1;
hochgezählt wird, dann wird diese Operation nicht atomar ausgeführt. Zwischen dem Lesen und dem Schreiben der Variable könnte ein weiterer Zugriff auf die Variable erfolgen.
Wenn der Zähler in mehreren Tasks hochgezählt wird, kann das Ergebnis der Zählung kleiner sein als die Anzahl der Zählvorgänge. Wenn also zwei Tasks den obigen Code einmal ausführen und die Variable zuvor den Wert 0
hatte, dann kann die Variable anschließend den Wert 1
haben. Das ist insbesondere dann problematisch, wenn Arrays in mehreren Tasks bearbeitet werden und in jeder Bearbeitung ein eindeutiger Index für das Array benötigt wird.
Die Operator __XADD
erhält beim Aufruf als ersten Summanden einen Pointer auf eine Variable vom Typ DINT
und als zweiten Summanden einen Wert vom Typ DINT
. __XADD
liefert den alten Wert des ersten Summanden zurück und addiert im selben Schritt den zweiten Summanden auf den ersten Summanden.
Beispielsweise kann der Aufruf der Funktion wie folgt aussehen: diOld := __XADD(ADR(diVar), deAdd);
Das folgende Beispiel zeigt eine typische Verwendung. Ein Array soll aus zwei Tasks gefüllt werden, dabei sollen alle Positionen im Array verwendet werden und keine Position überschrieben werden.
Mit dieser Funktion können mehrere Tasks ein boolsches Array füllen.
FUNCTION WriteToNextArrayPosition : BOOL VAR_EXTERNAL g_diIndex : DINT; // Index and array are globally defined and used by multiple tasks g_boolArray : ARRAY [0..1000] OF BOOL; END_VAR VAR_INPUT bToWrite : BOOL; END_VAR VAR diIndex : DWORD; END_VAR diIndex := __XADD(ADR(g_diIndex), 1); // Returns a unique index WriteToNextArrayPosition := FALSE; IF (diIndex >= 0 AND diIndex <= 1000) THEN g_boolArray[diIndex] := bToWrite; //Writes to unique index WriteToNextArrayPosition := TRUE; // TRUE: Array was not full yet END_IF