Mutex (mutual exclusion service) is a mechanism to control thread execution. This is a mechanism that can be used to prevent multiple threads from executing simultaneously in particular places in the program and from simultaneously accessing data, registers and other resources.
Mutex is initialized with OS_InitMutex()
The OSMutex structure is as follows:
struct OSMutex
{
OSThreadQueue queue;
OSThread* thread; // the current owner
s32 count; // lock count (notice: use upper 1byte as mutex type)
OSMutex* prev; // link for OSThread.queueMutex
OSMutex* next; // link for OSThread.queueMutex
};
|
The members prev and next manage mutex lists. The actual synchronous mutex functionality is done using the queue, thread, and count members.
queue is the thread queue where the thread that is being made to wait by mutex is registered.
thread is the member which registers the current thread that is locking other threads with this mutex.
count is the member that manages the lock nest for this mutex. It counts the number of times the lock has been set. However, the upper 1 byte is used to indicate the mutex type. The remaining 24 bits are used for the count value. The type is included in count instead of setting it to a separate member in order to retain compatibility with previous versions of mutex. (Note: Because the emphasis is on speed, the upper limit of the count value is not checked. One mutex can use 24 bits, which is equal to roughly 1.667 million nested levels. That limit will probably never be reached.)
The following section explains mutex types.
The mutex types are STD, R, and W. (These are defined in the header as OS_MUTEX_TYPE_STD and so forth. In the following explanation they are referred to as STD, R, and W.) If no type is specified, NONE is used.
For normal thread synchronization, a STD mutex is used. With this type of mutex, other threads are not permitted unconditional entry.
The R and W types are called read lock and write lock mutexes.
The read lock mutex does not allow other threads to perform write or standard mutex locks. This type can be used when data is read. Multiple threads can simultaneously read the data without problem, but a data-writing process at this point could compromise the data consistency.
The write lock mutex can be used when a thread is writing data. The data to be written cannot come from multiple threads. The W mutex does not permit another thread to read the data during the writing process. A W mutex has lock policy similar to that of a STD mutex. They are not exactly the same, because there are functions to change between read lock and write lock mutexes.
An R mutex can change to a W type, and a W mutex can change an R type, provided there is only one level of locking by the thread with the mutex. In the following example, after data is written the process immediately changes to reading without releasing the lock (thus permitting reading by another thread).
OSMutex mutex;
OS_InitMutex( &mutex );
void write_and_read()
{
OS_LockMutexW( &mutex ); write lock
writeData();
OS_LockMutexFromWToR( &mutex ); Change from write lock to read lock
readData();
OS_UnlockMutexR(); Unlock as a read lock
}
void read()
{
OS_LockMutexR( &mutex );
readData();
OS_UnlockMutexR( &mutex );
}
thread1()
{
write_and_read();
}
thread2()
{
read();
}
The following operations can be performed on a mutex after it has been initialized.
- Lock the mutex (Lock functions):
OS_LockMutex, OS_LockMutexR, OS_LockMutexW
- Unlock the mutex (Unlock functions):
OS_UnlockMutex, OS_UnlockMutexR, OS_UnlockMutexW, OS_UnlockMutexRW
- Attempt to lock the mutex (TryLock functions):OS_TryLockMutex, OS_TryLockMutexR, OS_TryLockMutexW
When you lock a mutex, other threads are blocked from locking that mutex. However, read lock mutexes do not block each other. A blocked thread waits for the mutex to be unlocked.
Lock functions wait until the lock is completed, but the TryLock functions return immediately, regardless of whether the mutex can be locked. You can determine from the returned value whether the lock was successful.
The following operations are available for read lock and write lock mutexes.
- Change the mutex type:
OS_LockMutexFromRToW, OS_LockMutexFromWToR
- Attempt to change the mutex type:
OS_TryLockMutexFromRToW, OS_TryLockMutexFromWToR
This section explains the internal operations when a mutex is locked.
When the mutex is initialized by the OS_InitMutex function, the owner of the OSMutex thread, the count value, the thread type, and the thread queue have the values shown in the following table. (The count member of OSMutex contains two pieces of information: the count value and the mutex type. This information is shown as count and type.)
This section explains locking with a standard mutex, not with a read lock/write lock mutex.
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 a OS_LockMutex()
For example, consider the figure below when there is a Mutex1 and a program which uses it for locking.
Suppose thread1 attempts to execute this program. thread1 executes the mutex lock function OS_LockMutex( &Mutex1 ). Because Mutex1 is not in use, thread 1 is recorded as the Mutex1 owner thread, the count is set to 1, and the program returns from the lock function. (The determination of whether Mutex1 is in use is based on whether the Mutex1 owner thread is NULL.)
Next, consider what happens when a separate thread, thread2, attempts to execute the same program. thread2 runs OS_LockMutex ( &Mutex1 )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 pause state. At this point, thread2 is registered inside the mutex1 thread queue as waiting for this lock to be released.
Now consider a case where thread1 once again runs OS_LockMutex ( &Mutex1 )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 pause state on the same line. If the mutex is unlocked, all registered threads will go into an executable state.
This section explains the internal operations when a mutex lock is unlocked. The explanation explains unlocking a standard mutex, not a read lock/write lock mutex.
The function used to unlocking a mutex is OS_UnlockMutex. However, calling this function does not always unlock the mutex. Only when the count value inside the mutex has decremented to 0 will the lock be released. If the value is not zero, count will only be decremented and control will return from the function.
For example, consider the following figure, where thread1 runs OS_LockMutex ( &Mutex1 )mutex1 to block thread2.
At this point, 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 example, thread2 goes into an executable state.
If thread2 has higher priority than thread1, the threads will be switched. In other words, thread1 will pause and thread2 will execute. In its previous attempt to execute OS_LockMutex( &Mutex1 ), thread2 was blocked by thread1. This time, however, because Mutex1 has been released and initialized, thread2 uses Mutex1 to block the other threads.
When thread1 runs OS_UnlockMutexthread1 can still continue. If this is the case, no thread re-scheduling occurs. In this way, mutex locks can take on a nested structure.
Until there is a lock, the OS_LockMutexOS_TryLockMutex
Use the OS_TryLockMutex
The following Try functions perform similarly.
- The OS_TryLockMutexR function corresponds with OS_LockMutexR.
- The OS_TryLockMutexW function corresponds with OS_LockMutexW.
- The OS_TryLockMutexFromRToW function corresponds with OS_LockMutexFromRToW.
- The OS_TryLockMutexFromWToR function corresponds with OS_LockMutexFromWToR.
When the thread ends, every mutex locked by that thread is unlocked. This is true not only for a standard mutex, but also for read lock/write lock mutexes.
When a function specifies a pointer to a mutex that is NULL or the call is clearly unusual in some other way, the DEBUG build will catch on the SDK_ASSERT function. If an unlock function is called for a mutex that has not been locked, 'Illegal unlock mutex' is displayed. If this message is displayed, verify that the lock and unlock levels accurately correspond. Note that this message is output by the SDK_TWarning function, so the program will not stop.
Overview of OS Functions (Exclusion Control)
2008/12/17 Revised contents to reflect read/write lock.
2004/12/14 Revised terminology and word endings.
2004/11/11 Initial version.
CONFIDENTIAL