# Mutual Exclusion

Mutual exclusion controls how many threads can simultaneously run a region of code. In oneAPI Threading Building Blocks (oneTBB), mutual exclusion is implemented by mutexes and locks. A mutex is an object on which a thread can acquire a lock. Only one thread at a time can have a lock on a mutex; other threads have to wait their turn.

The simplest mutex is `spin_mutex`. A thread trying to acquire a lock on a `spin_mutex` busy waits until it can acquire the lock. A `spin_mutex` is appropriate when the lock is held for only a few instructions. For example, the following code uses a mutex `FreeListMutex` to protect a shared variable `FreeList`. It checks that only a single thread has access to `FreeList` at a time.

    Node* FreeList;
    typedef spin_mutex FreeListMutexType;
    FreeListMutexType FreeListMutex;

    Node* AllocateNode() {
        Node* n;
        {
            FreeListMutexType::scoped_lock lock(FreeListMutex);
            n = FreeList;
            if( n )
                FreeList = n->next;
        }
        if( !n )
            n = new Node();
        return n;
    }

    void FreeNode( Node* n ) {
        FreeListMutexType::scoped_lock lock(FreeListMutex);
        n->next = FreeList;
        FreeList = n;
    }

The constructor for `scoped_lock` waits until there are no other locks on `FreeListMutex`. The destructor releases the lock. The braces inside routine `AllocateNode` may look unusual. Their role is to keep the lifetime of the lock as short as possible, so that other waiting threads can get their chance as soon as possible.

Caution

Be sure to name the lock object, otherwise it will be destroyed too soon. For example, if the creation of the `scoped_lock` object in the example is changed to

    FreeListMutexType::scoped_lock (FreeListMutex);

then the `scoped_lock` is destroyed when execution reaches the semicolon, which releases the lock before `FreeList` is accessed.

The following shows an alternative way to write `AllocateNode`:

    Node* AllocateNode() {
        Node* n;
        FreeListMutexType::scoped_lock lock;
        lock.acquire(FreeListMutex);
        n = FreeList;
        if( n )
            FreeList = n->next;
        lock.release();
        if( !n )
            n = new Node();
        return n;
    }

Method `acquire` waits until it can acquire a lock on the mutex; method `release` releases the lock.

It is recommended that you add extra braces where possible, to clarify to maintainers which code is protected by the lock.

If you are familiar with C interfaces for locks, you may be wondering why there are not simply acquire and release methods on the mutex object itself. The reason is that the C interface would not be exception safe, because if the protected region threw an exception, control would skip over the release. With the object-oriented interface, destruction of the `scoped_lock` object causes the lock to be released, no matter whether the protected region was exited by normal control flow or an exception. This is true even for our version of `AllocateNode` that used methods `acquire` and `release –` the explicit release causes the lock to be released earlier, and the destructor then sees that the lock was released and does nothing.

All mutexes in oneTBB have a similar interface, which not only makes them easier to learn, but enables generic programming. For example, all of the mutexes have a nested `scoped_lock` type, so given a mutex of type `M`, the corresponding lock type is `M::scoped_lock`.

Tip

It is recommended that you always use a `typedef` for the mutex type, as shown in the previous examples. That way, you can change the type of the lock later without having to edit the rest of the code. In the examples, you could replace the `typedef` with `typedef queuing_mutex FreeListMutexType`, and the code would still be correct.

- Mutex Flavors
- Reader Writer Mutexes
- Upgrade/Downgrade
- Lock Pathologies