Exclusion Control (Mutex) (Overview)


Introduction

Mutex (mutual exclusion (service)) is a mechanism for exclusion control among threads. For particular program locations, this mechanism curbs simultaneous execution from multiple threads and sees that resources such as data and registers are not accessed simultaneously from multiple threads.


Initializing Mutex

Mutex is initialized with OS_InitMutex(). One mutex can be configured for each OSMutex structure object.


The Mutex Structure

The OSMutex structure is as follows:

  struct OSMutex
  {
      OSThreadQueue   queue;
      OSThread*       thread; // the current owner
      s32             count;  // lock count

      OSMutex*        prev;   // link for OSThread. queueMutex  
      OSMutex*        next;   // link for OSThread. queueMutex
  };
      

 

Of these, prev and next are arguments for management of the mutex list structure. The queue, thread, and count arguments perform the actual mutex functions.

queue is the thread queue where the thread that is being made to wait by mutex is registered.

thread is the argument which registers the current thread that is locking other threads with this mutex.

count is the argument that manages the lock nest for this mutex.

Each argument takes the value indicated below when initializing mutex.


Locking Mutex

The lock function preformed by mutex is OS_LockMutex().

If OS_LockMutex() is called in a program and the designated mutex is not being used in a lock at that point in time, OS_LockMutex records and locks the current thread.

If you encounter an OS_LockMutex() call for an already locked mutex, the mutex is bypassed if it is being locked by the same thread as the current thread. If the thread is not the same, it will go into a sleep state until unlocked. Thread re-scheduling occurs at this time.

For example, consider the figure below when there is a Mutex1 and a program which uses it for locking.

Thread1 attempts to execute this program. Thread1 encounters the mutex lock function OS_LockMutex ( &Mutex1 ), but since mutex1 has not yet been used at this point in time (this decision assumes that the mutex1 owner thread is NULL), thread 1 is recorded as the mutex1 owner thread, the count is set to 1, and it returns from the lock function.

Next, consider what happens when a separate thread, thread2, attempts to execute the same program. thread2 also encounters OS_LockMutex ( &Mutex1 ), but mutex1 is already being used in a lock. Since thread2 is not the mutex1 owner thread, thread2 cannot proceed any further. As a result, thread2 goes into a sleep state. At this point, it is a thread inside the mutex1 thread queue waiting for this lock to be unlocked, so go ahead and register thread2.

Now consider a case where thread1 once again encounters OS_LockMutex ( &Mutex1 ) (whether it is on the same line or a different line). mutex1 is already being used in a lock, but the mutex1 owner thread is the same as the current thread (thread1), so it can be bypassed. When this happens, the mutex1 count increments.

There are also times when multiple threads are registered in a single mutex thread queue. These threads are all locked by that mutex. However, it is not necessarily the case that all threads are in a sleep state in the same location. If the mutex is unlocked, all registered threads will go into an executable state. (This will be described later).


Unlocking Mutex

The function used for unlocking with mutex is OS_UnlockMutex().

However, unlocking does not always occur. The unlocking only takes place when the decremented count value inside the mutex is zero. When the count value is not zero, that value is simply decremented, and control is returned from the function.

For example, consider the case in the figure below where thread1 encounters OS_LockMutex ( &Mutex1 ) while thread1 is in a state where it is using mutex1 to lock thread2.

At this time, the count has been decremented to zero, so the thread registered in the thread queue is put into an executable state and is re-scheduled. In this case, thread2 goes into an executable state.

If the priority of thread2 is higher than that of thread1, thread1 goes to sleep and thread2 goes into an executable state. Therefore, thread2 will execute OS_LockMutex(). As a result, thread2 will subsequently use mutex1 to lock other threads.

Going back, even if using OS_UnlockMutex() to decrement the count value, if that value is not zero it can be considered that there are other locks that have not been unlocked, and this can be bypassed. If this is the case, no thread re-scheduling occurs. In this way, it does not matter if the lock and unlock are nested.


Attempting to Lock Mutex

Until there is a lock, OS_LockMutex() does not return from the function, but on the other hand OS_TryLockMutex() is a function which locks if it can, but which returns immediately if it can't lock.

With OS_TryLockMutex(), you can learn whether or not the lock was a success from its return value.


When the Thread Ends...

When the thread ends, every mutex locking that thread is unlocked.

See Also

An Overview of OS Functions (Exclusion Control )

Revision History

11/11/2004 Initial version