Loki: Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy > Class Template Reference

# Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy > Class Template Reference

`#include <LevelMutex.h>`

Inheritance diagram for Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >:
[legend]
Collaboration diagram for Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >:
[legend]

List of all members.

## Public Member Functions
| LevelMutex (unsigned int level=DefaultLevel)
| ~LevelMutex (void)
| The destructor.
const volatile MutexPolicy & | GetMutexPolicy (void) const volatile
virtual MutexErrors::Type | TryLock (void) volatile
virtual MutexErrors::Type | Lock (void) volatile
virtual MutexErrors::Type | Lock (unsigned int milliSeconds) volatile
virtual MutexErrors::Type | Unlock (void) volatile

## Detailed Description

### template<class MutexPolicy, unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>
class Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >

Levelized mutex class prevents deadlocks by requiring programs to lock mutexes in the same order, and unlock them in reverse order. This is accomplished by forcing each mutex to have a level and forcing code to lock mutexes with higher levels before locking mutexes at lower levels. If you want to lock several mutexes, they must be locked in decreasing order by level, or if they are all of the same level, then locked by LevelMutex::MultiLock.

Features
  - Immune: Very unlikely to deadlock since all mutexes are locked in the same order and unlocked in reverse order.
  - Scalable: Can handle any number of mutexes.
  - Efficient: Many operations occur in constant time, and most operations require no more than O(m) steps.
  - Exception safe: All operations provide strong safety or don't throw.
  - Extendable: Can work with existing mutexes through policy-based design.
  - Easily Extended: Derived classes only need to implement 5 functions and a mutex to get all the features of this class.
  - Re-Entrant: Allows for re-entrancy even if mutexes in policy classes don't.
  - Cost-Free: No resource allocations occur in LevelMutex - although user-defined policy classes may allocate resources.
  - Compact: Each LevelMutex object is small.
  - Portable: As long as your compiler and libraries can meet the requirements.
  - Robust: Maintains data integrity even if exceptions occur in policy classes.
  - Affording: Several functions provide information about a mutex which allows client code to easily choose correct actions.

Requirements
  - Your compiler must allow for thread-specific data.
  - You must have a threading or mutex library.

Policy-Based Design
  This class hosts 3 policies and a default level. The policy-based design allows users to write their own policies to extend the behaviors of LevelMutex. The paragraphs below say how to design a class for each policy.
  - MutexPolicy The mutex policy class.
  - defaultLevel A level for existing client code that calls a default constructor.
  - ErrorPolicy How the mutex should handle error conditions.
  - WaitPolicy Whether a thread should wait, and how long in some internal loops.

MutexPolicy
  A policy class that wraps a low-level mutex. Loki provides two policy classes for the actual mutex (SpinLevelMutex and SleepLevelMutex), both of which wrap either pthreads or the Windows CRITICAL_SECTION. If you want to use a mutex mechanism besides one of those, then all you have to do is provide a class which wraps the mutex and implements these functions. explicit SpinLevelMutex( unsigned int level ); virtual ~SpinLevelMutex( void ); virtual MutexErrors::Type Lock( void ) volatile; virtual MutexErrors::Type TryLock( void ) volatile; virtual MutexErrors::Type Unlock( void ) volatile; Indeed, since the base class does most of the work, and provides all the interace and functionality to client classes, a derived class has very few requirements. It only needs to implement a single constructor, the destructor, some virtual functions, and whatever data members it requires. You don't actually need to declare those functions as virtual if the policy class is not a base or child class. In the parlance of design patterns, LevelMutex is a Template, and the MutexPolicy is a Strategy.

DefaultLevel
  The template class requires a default level to use inside the default constructor. Some existing code calls instantiates mutexes with a default constructor, so the mutex must know what level to use there. Please do not use zero or UnlockedLevel as the default level.

ErrorPolicy
  This policy specifies how to handle error conditions. The mutexes can return errors, assert, or throw exceptions. I recommend that debug code use asserts, release code use exceptions, and unit-testing code just return errors. The error policy class only needs to implement one function: static MutexErrors::Type CheckError( MutexErrors::Type error, unsigned int level );

WaitPolicy
  This states whether the mutex should wait within some tight internal loops, how the waiting is done, and for how long. A wait policy class could sleep, do nothing, check if other objects need attention, or check if the program received events or notices from the operating system. It only needs to implement one function: static void Wait( void );

Per-Function Usage
  If you implement a function with a static local mutex, then you have to insure the function is not called from a lower level via call-backs, virtual functions in interface classes. If the function does get called from a lower level, you are setting up a potential deadlock. LevelMutex will detect that by checking the current level and the local mutex's level, so it will refuse to lock the local mutex.

Per-Object Usage
  If you use a mutex as a data member of an object to protect that object, then I recommend specifying which functions are volatile and which are not, and then only use the mutex within the volatile functions. You may also want to provide accessor functions so that client code can lock and unlock the mutex either to allow for calling multiple operations without having to lock and unlock before and after each operation, or so they can lock it along with several other objects at the same level.

Per-Class Usage
  If you make a static data member within a class, you can use that to lock any resources shared by those objects, or to require threads to act on only one object at a time. You may also want to provide static accessor functions so that client code can lock several other resources at the same level.

## Constructor & Destructor Documentation

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::LevelMutex | ( | unsigned int | level = `DefaultLevel` | ) | `[inline, explicit]`

This constructor allows callers to replace the default level with another value. It also acts as the default constructor for existing code which uses default construction for mutexes. This is the only time the DefaultLevel template parameter gets used.

References Loki::LevelMutexInfo::IsValid().

Here is the call graph for this function:

## Member Function Documentation

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

const volatile MutexPolicy& Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::GetMutexPolicy | ( | void |  | ) | const volatile`[inline]`

These functions allow callers to access the mutex in case they need to modify specific values in the MutexPolicy (e.g. - sleep time, functors to call as tasks, etc...) There is one function for every combination of const and volatile qualifiers so callers get a reference to a MutexPolicy with the proper qualifiers.

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

virtual MutexErrors::Type Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::Lock | ( | unsigned int | milliSeconds | ) | volatile`[inline, virtual]`

Attempts to lock mutex, but only waits for a limited amount of time before it gives up. Will return quickly if an error occurs before any attempt to lock. This may throw an exception if the lock failed or an error occurred - if that is what the error policy specifies.

Parameters:

  | milliSeconds | How long to wait.

Returns:
  An error condition if any occurred, else Success.

Implements Loki::LevelMutexInfo.

References Loki::LevelMutexInfo::GetLevel(), Loki::LevelMutexInfo::IsLockedByCurrentThread(), Loki::LevelMutexInfo::IsValid(), and Loki::LevelMutexInfo::PostLock().

Here is the call graph for this function:

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

virtual MutexErrors::Type Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::Lock | ( | void |  | ) | volatile`[inline, virtual]`

Blocking call will attempt to lock mutex and wait until it can lock. This may throw an exception if the lock failed or an error occurred - if that is what the error policy specifies.

Returns:
  An error condition if any occurred, else Success.

Implements Loki::LevelMutexInfo.

References Loki::LevelMutexInfo::GetLevel(), Loki::LevelMutexInfo::IsLockedByCurrentThread(), Loki::LevelMutexInfo::IsValid(), and Loki::LevelMutexInfo::PostLock().

Here is the call graph for this function:

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

virtual MutexErrors::Type Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::TryLock | ( | void |  | ) | volatile`[inline, virtual]`

Tries to lock mutex, and returns immediately if mutex already locked by another thread. It will return immediately with a value of AlreadyLocked if the mutex was locked by a different thread. It may throw an exception or assert when errors occur if the ErrorPolicy class implements that behavior.

Returns:
  An error condition if any occurred, else Success.

Implements Loki::LevelMutexInfo.

References Loki::LevelMutexInfo::GetLevel(), Loki::LevelMutexInfo::GetLockCount(), Loki::LevelMutexInfo::IsValid(), and Loki::LevelMutexInfo::PostLock().

Here is the call graph for this function:

template<class MutexPolicy , unsigned int DefaultLevel, class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, class WaitPolicy = ::Loki::NoMutexWait>

virtual MutexErrors::Type Loki::LevelMutex< MutexPolicy, DefaultLevel, ErrorPolicy, WaitPolicy >::Unlock | ( | void |  | ) | volatile`[inline, virtual]`

Unlocks the mutex, or returns an error condition. This may throw an exception if the lock failed or an error occurred - if that is what the error policy specifies.

Returns:
  An error condition if any occurred, else Success.

Implements Loki::LevelMutexInfo.

References Loki::LevelMutexInfo::GetLevel(), Loki::LevelMutexInfo::IsValid(), Loki::LevelMutexInfo::PostLock(), and Loki::LevelMutexInfo::PreUnlock().

Here is the call graph for this function:

The documentation for this class was generated from the following file:

- LevelMutex.h