Mutex
- Namespace
- ZPlatform
- Implements
FUNCTION_BLOCK Mutex IMPLEMENTS ZCore.IMutex
Mutex implements a simple locking mechanism by utlizing a test-and-set instruction combined with an external owner handle. There are two main purposes for using this object
Mutual exclusion to prevent race conditions when using multiple tasks by using Lock. It is required that one task of execution never enters a critical section while a concurrent task of execution is already accessing critical section, which refers to an interval of time during which a thread of execution accesses a shared resource, such as Shared-data-objects, shared-resources, shared-memory. For instance, when using a Logger in an application the methods for writing a line into a file are not thread-safe. Without locking, there could be unexpected behavior when two tasks simultaneously add a new message to the logger. This particular problem is solved by the Logging function block, which internally uses a Mutex instance by guarding every call to a logging method with a mutex lock.
IF _mutex.Lock(THIS^) THEN _logger.Info('Text'); _mutex.Unlock(THIS^); END_IFTaking ownership of an object to execute a set of actions and block others from accessing the object. This use-case is PLC specific, because in general, PLC calls are not blocking. For example, when we move an axis from A to B, we have to start the movement in 1 PLC cycle and poll the position for each following cycle until the axis actually reached position B. In a sense, all actions that are performed in a PLC are concurrent within 1 PLC cycle. In the previous example, a Mutex instance can be used to block others from starting a movement once a movement command is already in order.
IF _step.OnEntry() THEN // Try to get a lock to the mutex, if this fails, try again the next cycle IF NOT _mutex.TryLock(THIS^) THEN _step.RepeatStep(); RETURN; END_IF _axis.MoveAbsoluteAsync(position:=100, speed:=1); END_IF IF _axis.Done THEN _mutex.Unlock(THIS^); END_IF
Please note, that while the first purpose of a Mutex, which utilizes the Lock method, is usually only relevant if multiple tasks are used in a PLC. However, the second purpose of a Mutex is also relevant for PLCs with only one task, because of the concurrent nature of PLCs.
Methods
IsLocked
METHOD IsLocked () : BOOL
Return if this mutex got locked by any potential owner. Use IsLockedBy for querying the state of a specific potential owner.
This method is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Returns
- BOOL
IsLockedBy
METHOD IsLockedBy (
[input] locker : ZCore.ZPointer) : BOOL
This method returns TRUE if this mutex is locked by a specific object. If
the actual object is not of particular interest, the method IsLocked
may be used instead.
This method is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Inputs
lockerZPointer
Returns
- BOOL
Lock
METHOD Lock (
[input] locker : ZCore.ZPointer) : BOOL
Lock the Mutex where the owner of the instance that wants to lock the Mutex
is given by a number. Usually it is either an enum entry that is uniquely linked to a locker
or simply a pointer to the locker by using THIS^ as parameter for the method.
This method blocks the current thread until the lock can be achieved and should be used with special care! To be specific, this method should only be used to guard calls that are finished in << 1 cycle. It is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Warning
Even though this lock is blocking the current task, the method can still return FALSE when
another Task is in a breakpoint or if the mutex is locked by a different locker.
Warning
Lock utilizes FB_IecCriticalSection, which is not available on every hardware. For instance, it is not supported by the following targets
- Devices with Windows CE before TwinCAT 3.1.4022.29
- TwinCAT's Usermode Runtime
When using Lock in a PLC that uses more than 1 task, on a target that is not supported by FB_IecCriticalSection,
this method will always return FALSE.
Inputs
lockerZPointer
Returns
- BOOL
TryLock
METHOD TryLock (
[input] locker : ZCore.ZPointer,
[input] recursive : BOOL) : BOOL
Try to lock the Mutex where the owner of the instance that wants to lock the Mutex
is given by a number. Usually it is either an enum entry that is uniquely linked to a locker
or simply a pointer to the locker by using THIS^ as parameter for this method.
_mutex.TryLock(THIS^);
This method will only succeed (return TRUE), if the locker already has ownership of this Mutex (only for recursive=true)
or if the Mutex is not locked by any other party at the moment (regardless of the recursive parameter)
This method is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Inputs
lockerZPointerrecursiveBOOLrecursive=truedoesn't care if the object is already locked by locker (method returnstruein that case)
Returns
- BOOL
TryLockTransfer
METHOD TryLockTransfer (
[input] locker : ZCore.ZPointer,
[input] recursive : BOOL,
[input] lockerDst : ZCore.ZPointer) : BOOL
Try to lock the Mutex (same as TryLock) -
if successful, the lock is directly passed to another locker. In contrast to
unlocking the Mutex first from owner1 and then locking it with owner2, this
method ensures that owner2 will get the lock. If locker=0 this
method will fail.
The method is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Inputs
lockerZPointerrecursiveBOOLrecursive=truedoesn't care if the object is already locked by locker (method returnstruein that case)lockerDstZPointer
Returns
- BOOL
Unlock
METHOD Unlock (
[input] locker : ZCore.ZPointer) : BOOL
With this method one can try to unlock the Mutex. The owner of the instance that wants to unlock the Mutex
is given by a number. Usually it is either an enum entry that is uniquely linked to a locker
or simply a pointer to the locker by using THIS^ as parameter for this method.
_mutex.Unlock(THIS^);
This method will succeed only (return TRUE), if the locker already has ownership of this Mutex
or if the Mutex is not locked by any other party at the moment.
The method is thread-safe and therefore may be used from multiple tasks and also on different CPU-cores at once.
Note
It is save to call this method even if locker is not the owner of this Mutex at the moment. In this case, this method will simply return without changing anything for the Mutex instance.
Inputs
lockerZPointer
Returns
- BOOL