PCL
|
Adaptive mutual exclusion lock variable. More...
#include <Mutex.h>
Public Member Functions | |
Mutex (const Mutex &)=delete | |
Mutex (int spinCount=4000, int spinCountDelta=1000, int spinCountMax=12000) | |
virtual | ~Mutex () |
void | Lock () |
void | operator() (bool lock=true) |
Mutex & | operator= (const Mutex &)=delete |
int | SpinCount () const |
bool | TryLock () |
void | Unlock () |
The word mutex is an abbreviation for mutual exclusion. A mutex object provides access synchronization for threads. A mutex protects one or more objects or a code section, so that only one thread can access them at a given time.
To understand how mutual thread exclusion works and why is it needed, consider the following example code:
If functionOne() and functionTwo() are called in sequence, this happens:
Now suppose that we define two threads that call the above functions:
If we start both threads in sequence:
then the following might happen:
Because both threads can access data in any order, and there is no guarantee as to when a given thread starts execution, the result may not be what we expect (we get 12 instead of 21). Adding synchronization with a Mutex object in functionOne() and functionTwo() solves the problem:
A mutex can only be locked by a single thread at a time. After Lock() has been called from a thread T, other threads that call Lock() on the same mutex object block their execution until the thread T calls Unlock().
To attempt locking a mutex without blocking execution, the Mutex::TryLock() member function can be used. This can provide much higher performance than Mutex::Lock() when the calling threads don't depend on gaining exclusive access to the shared data being protected by the mutex object.
Mutex implements adaptive spinning, a technique that can improve performance by avoiding expensive semaphore wait operations under high levels of thread contention. See the documentation for the class constructor for more information.
Mutex has been implemented as a low-level PCL class that does not depend on the PixInsight core application. On Windows platforms, Mutex has been implemented as a wrapper to a critical section. On UNIX/Linux platforms, Mutex uses atomic integer operations implemented as inline assembly code and direct calls to the pthreads library.
|
inline |
Constructs a Mutex object.
spinCount | Maximum number of spinning loops to do before performing a mutex semaphore wait operation when a thread attempts to lock this mutex and it has already been locked by another thread. The expensive wait operation can be avoided if this object becomes unlocked during the spinning loops. The spin count must be ≥ 0. When this parameter is zero, a regular non-spinning mutex is constructed. The default value is 4000. |
spinCountDelta | When spinCount > 0, this is an increment applied to the maximum number of spinning loops when the spinning process fails and an expensive mutex lock operation is performed because not enough loops were executed. This parameter allows for an adaptive spin lock mutex operation by increasing the number of loops when necessary. The default value is 1000. |
spinCountMax | When both spinCount and spinCountDelta are greater than zero, this is the upper bound of spinning loops allowed by adaptively increasing them when the loops are insufficient to avoid an expensive mutex lock operation. The default value is 12000. |
|
inlinevirtual |
|
delete |
Copy constructor. This constructor is disabled because mutexes are unique objects.
|
inline |
Locks this Mutex object.
When a mutex has been locked in a thread T, other threads cannot lock it until the thread T unlocks it. When a thread attempts to lock a Mutex object that has been previously locked, it blocks its execution until the Mutex object is unlocked.
If the mutex has already been locked by another thread, this routine performs a number of spin loops before doing an (expensive) wait operation on a semaphore associated with this mutex object. If this mutex becomes unlocked during the spinning loops, the wait operation can be avoided to lock the mutex in the calling thread. This can greatly improve efficiency of multithreaded code under high levels of contention (e.g. several running threads that depend on frequent concurrent accesses to shared data). For fine control and performance tuning, the maximum number of spinning loops can be specified in the class constructor, as well as an increment for adaptive spinning and the maximum spinning loops allowed by increasing them adaptively.
|
inline |
Function call operator. This is a convenience operator that performs the lock and unlock operations in an alternative, perhaps more elegant way.
lock | Whether the mutex should be locked (when true) or unlocked (when lock is false). |
For example, the following code snippet:
is equivalent to:
Copy assignment. This operator is disabled because mutexes are unique objects.
|
inline |
Returns the current spin count of this Mutex object.
The spin count is a read-only property that can only be set upon object construction. It can grow adaptively after successive mutex lock operations. For information on mutex spin counts, refer to the class constructor.
|
inline |
Attempts locking this Mutex object. Returns true iff this mutex has been successfully locked because no other thread had already acquired it.
Unlike Lock(), this function does not block execution of the calling thread if this mutex cannot be locked.
Definition at line 389 of file Mutex.h.
Referenced by pcl::AbstractImage::RunThreads().
|
inline |
Unlocks this Mutex object.
See the Lock() documentation for more information.
Definition at line 337 of file Mutex.h.
Referenced by pcl::AbstractImage::RunThreads().