[For complete, up-to-date TBB information visit: http://www.ThreadingBuildingBlocks.org]
Mutexes provide MUTual EXclusion of threads from sections of code.
In general, strive for designs that minimize the use of explicit locking, because it can lead to serial bottlenecks. If explicitly locking is necessary, try to spread it out so that multiple threads usually do not contend to lock the same mutex.
The mutexes and locks here have relatively spartan interfaces that are designed for high performance. The interfaces enforce the scoped locking pattern, which is widely used in C++ libraries because:
1. Does not require the programmer to remember to release the lock
2. Releases the lock if an exception is thrown out of the mutual exclusion region protected by the lock
There are two parts to the pattern: a mutex object, for which construction of a lock object acquires a lock on the mutex and destruction of the lock object releases the lock. Here’s an example:
{
// Construction of myLock acquires lock on myMutex
M::scoped_lock myLock( myMutex );
... actions to be performed while holding the lock ...
// Destruction of myLock releases lock on myMutex
}
If the actions throw an exception, the lock is automatically released as the block is exited.
Table 19 shows the requirements for the Mutex concept for a mutex type M
Header
#include "tbb/queuing_mutex.h"
Description
A queuing_mutex models the Mutex Concept ( 6.1.1). A queuing_mutex is scalable, in the sense that if a thread has to wait to acquire the mutex, it spins on its own local cache line. A queuing_mutex is fair. Threads acquire a lock on a mutex in the order that they request it. A queuing_mutex is not reentrant.
The current implementation does busy-waiting, so using a queuing_mutex may degrade system performance if the wait is long.
Members
See Mutex Concept ( 6.1.1).
The ReaderWriterMutex concept extends the Mutex concept to include the notion of reader-writer locks. It introduces a boolean parameter write that specifies whether a writer lock (write =true) or reader lock (write =false) is being requested. Multiple reader locks can be held simultaneously on a ReaderWriterMutex if it does not have a writer lock on it. A writer lock on a ReaderWriterMutex excludes all other threads from holding a lock on the mutex at the same time.
Table 21 shows the requirements for ReaderWriterMutex RW.
Table 21: ReaderWriterMutex Concept
Pseudo-Signature
Semantics
RW()
Construct unlocked mutex
~RW()
Destroy unlocked mutex
typename RW::scoped_lock
Corresponding scoped-lock type
RW::scoped_lock()
Construct lock without acquiring mutex
RW::scoped_lock(RW&, bool write=true)
Construct lock and acquire lock on mutex
RW::~scoped_lock()
Release lock (if acquired)
RW::scoped_lock::acquire(RW&, bool write=true)
Acquire lock on mutex
bool RW::scoped_lock::try_acquire(RW&, bool write=true)
Try to acquire lock on mutex. Return true if lock acquired, false otherwise.
RW::scoped_lock::release()
Release lock
bool RW::scoped_lock::upgrade_to_writer()
Change reader lock to writer lock
bool RW::scoped_lock::downgrade_to_reader()
Change writer lock to reader lock
The following subsections explain the semantics of the ReaderWriterMutex concept in detail.
Model Types
spin_rw_mutex ( 6.1.6) and queuing_rw_mutex ( 6.1.7) model the ReaderWriterMutex concept.
6.1.5.1 ReaderWriterMutex()
Effect
Construct unlocked ReaderWriterMutex.
6.1.5.2 ~ReaderWriterMutex()
Effect
Destroy unlocked ReaderWriterMutex. The effect of destroying a locked ReaderWriterMutex is undefined.
6.1.5.3 ReaderWriterMutex::scoped_lock()
Effect
Construct a scoped_lock object that does not hold a lock on any mutex.
6.1.5.4 ReaderWriterMutex::scoped_lock( ReaderWriterMutex& rw, bool write =true)
Effect
Construct a scoped_lock object that acquires a lock on mutex rw. The lock is a writer lock if write is true; a reader lock otherwise.
6.1.5.5 ReaderWriterMutex::~scoped_lock()
Effect
If the object holds a lock on a ReaderWriterMutex, release the lock.
6.1.5.6 void ReaderWriterMutex:: scoped_lock:: acquire( ReaderWriterMutex& rw, bool write=true )
Effect
Acquires a lock on mutex rw. The lock is a writer lock if write is true; a reader lock otherwise.
6.1.5.7 bool ReaderWriterMutex:: scoped_lock::try_acquire( ReaderWriterMutex& rw, bool write=true )
Effect
Attempts to acquire a lock on mutex rw. The lock is a writer lock if write is true; a reader lock otherwise.
Returns
true if the lock is acquired, false otherwise.
6.1.5.8 void ReaderWriterMutex:: scoped_lock::release()
Effect
Release lock. The effect is undefined if no lock is held.
6.1.5.9 bool ReaderWriterMutex:: scoped_lock::upgrade_to_writer()
Effect
Change reader lock to a writer lock. The effect is undefined if the object does not already hold a reader lock.
Returns
false if lock was released and reacquired; true otherwise.
6.1.5.10 bool ReaderWriterMutex:: scoped_lock::downgrade_to_reader()
Effect
Change writer lock to a reader lock. The effect is undefined if the object does not already hold a writer lock.
Returns
false if lock was released and reacquired; true otherwise.
NOTE: Intel's current implementations for spin_rw_mutex and queuing_rw_mutex always return true. Different implementations might sometimes return false.
Summary
Class that models ReaderWriterMutex Concept that is unfair and not scalable.
Syntax
class spin_rw_mutex;
Header
#include "tbb/spin_rw_mutex.h"
Description
A spin_rw_mutex models the ReaderWriterMutex Concept ( 6.1.1). A spin_rw_mutex is not scalable, fair, or reentrant. It is ideal when the lock is lightly contended and is held for only a few machine instructions. If a thread has to wait to acquire a spin_rw_mutex, it busy waits, which can degrade system performance if the wait is long. However, if the wait is typically short, a spin_rw_mutex significantly improve performance compared to other mutexes..
Members
See ReaderWriterMutex concept ( 6.1.5).
Summary
Class that models ReaderWriterMutex Concept that is fair and scalable.
Syntax
class queuing_rw_mutex;
Header
#include "tbb/queuing_rw_mutex.h"
Description
A queuing_rw_mutex models the ReaderWriterMutex Concept ( 6.1.1). A queuing_rw_mutex is scalable, in the sense that if a thread has to wait to acquire the mutex, it spins on its own local cache line. A queuing_rw_mutex is fair. Threads acquire a lock on a queuing_rw_mutex in the order that they request it. A queuing_rw_mutex is not reentrant.
Members
See ReaderWriterMutex concept ( 6.1.5).
[For complete, up-to-date TBB information visit: http://www.ThreadingBuildingBlocks.org]