PTypes: multithreading: mutex

Top: Multithreading: mutex

>     #include <pasync.h>

>     class mutex {
>         mutex();

>         void enter();
>         void leave();

>         void lock();      // alias for enter()
>         void unlock();    // alias for leave()
>     }

>     class scopelock {
>         scopelock(mutex&);
>         ~scopelock();
>     }

Mutex (mutual exclusion) is another synchronization object which helps to protect shared data structures from being concurrently accessed and modified.

Accessing and changing simple variables like int concurrently can be considered safe provided that the variable is aligned on a boundary "native" to the given CPU (32 bits on most systems). More often, however, applications use more complex shared data structures which can not be modified and accessed at the same time. Otherwise, the logical integrity of the structure might be corrupt from the "reader's" point of view when some other process sequentially modifies the fields of a shared structure.

To logically lock the part of code which modifies such complex structures the thread creates a mutex object and embraces the critical code with calls to enter() and leave(). Reading threads should also mark their transactions with enter() and leave() for the same mutex object. When either a reader or a writer enters the critical section, any attempt to enter the same section concurrently causes the thread to "hang" until the first thread leaves the critical section.

If more than two threads are trying to lock the same critical section, mutex builds a queue for them and allows threads to enter the section only one by one. The order of entering the section is platform dependent.

To avoid infinite locks on a mutex object, applications usually put the critical section into try {} block and call leave() from within catch {} in case an exception is raised during the transaction. The scopelock class provides a shortcut for this construct: it automatically locks the specified mutex object in its constructor and unlocks it in the destructor, so that even if an exception is raised inside the scope of the scopelock object leave() is guaranteed to be called.

More often applications use a smarter mutual exclusion object called read/write lock -- rwlock.

PTypes' mutex object encapsulates either Windows CRITICAL_SECTION structure or POSIX mutex object and implements the minimal set of features common to both platforms. Note: mutex may not be reentrant on POSIX systems, i.e. a recursive lock from one thread may cause deadlock.

mutex::mutex() creates a mutex object.

void mutex::enter() marks the start of an indivisible transaction.

void mutex::leave() marks the end of an indivisible transaction.

void mutex::lock() is an alias for enter().

void mutex::unlock() is an alias for leave().

scopelock::scopelock(mutex& m) creates a scopelock object and calls enter() for the mutex object m.

scopelock::~scopelock() calls leave() for the mutex object specified during construction and destroys the scopelock object.

See also: thread, rwlock, trigger, semaphore, Examples

PTypes home