The following examples shows basic usage of a Intel TBB mutex to protect a shared variable named count using simple mutexes and scoped locks:
Simple Mutex Example
#include <tbb/mutex.h> int count; tbb::mutex countMutex; int IncrementCount() { int result; // Add Intel TBB mutex countMutex.lock(); // Implements ANNOTATE_LOCK_ACQUIRE() result = count++; // Save result until after unlock countMutex.unlock(); // Implements ANNOTATE_LOCK_RELEASE() return result; }
The semantics of countMutex.lock() and unlock() on countMutex correspond directly to the annotations ANNOTATE_LOCK_ACQUIRE() and ANNOTATE_LOCK_RELEASE(). However, it is generally better to use the scoped locking pattern.
Scoped Lock Example
With a scoped lock, you construct a temporary scoped_lock object that represents acquisition of a lock. Destruction of the scoped_lock object releases the lock on the mutex.
The following code shows the previous example rewritten using scoped locking:
#include <tbb/mutex.h> int count; tbb::mutex countMutex; int IncrementCount() { int result; { // Add Intel TBB scoped lock at location of ANNOTATE_LOCK annotations tbb::mutex::scoped_lock lock(countMutex); // Implements ANNOTATE_LOCK_ACQUIRE() result = count++; // Implicit ANNOTATE_LOCK_RELEASE() when leaving the scope below. } // scoped lock is automatically released here return result; }
The scoped_lock
pattern is preferred because it releases the lock no matter how control leaves the block. The scoped lock is released when destruction of the scoped_lock
object occurs. In particular, it releases the lock even when control leaves because an exception was thrown.
Intel TBB also has a tbb::atomic
template class that can be used in simple cases such as managing a shared integer variable. Check the Related Information for details.