Mutex object (Mutex)The kernel object can ensure that the thread has mutex access to a single resource.
A mutex object contains a quantity, a thread ID, and a recursive counter.
The behavior of the mutex object is the same as that of the key code segment, but the mutex object belongs to the kernel object, and the key code segment belongs to the user mode object.
This means that mutex objects run slowly than key code segments. However, this also means that multiple threads in different processes can access a single mutex object, and this means that a timeout value can be set when the thread is waiting to access the resource.
IDUsed to identify which thread in the system currently has a mutex object,
Recursive counterIndicates the number of times that the thread has mutex.
Purpose:
Generally, they are used to protect memory blocks accessed by multiple threads. If multiple threads need to access the memory block at the same time, the data in the memory block may be damaged. The mutex object can ensure that any thread accessing the memory block has exclusive access to the memory block, thus ensuring data integrity.
The rules for using mutex objects are as follows:
• If the thread ID is 0 (this is an invalid ID), the mutex object is not owned by any thread and sends a notification to this mutex object.
• If I D is a non-zero number, a thread will have a mutex object and will not send a notification to this mutex object.
• Unlike all other kernel objects, mutex objects have special code in the operating system, allowing them to violate normal rules.
To use a mutex object, a process must first callCreateMutexTo create a mutex:
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOLfInitialOwner,
PCTSTRpszName);
The PSA and pszname parameters are the security attributes of the kernel object and the name of the kernel object,
FInitialOwnerParameters are used to control the initial status of mutex objects.
IfFALSE(This is usually the value passed), so the ID and recursive counter of the mutex object are set to 0. This means that the mutex object is not owned by any thread. ThereforeSends its notification Signal.
IfTRUEThe thread ID of the object is set to the ID of the calling thread, and the recursive counter is set to 1. Because the ID is a non-zero number, when the mutex object startsNo notification Signal.
By callingOpenMutexThe other process can obtain the handle related to its own process and the existing mutex object:
HANDLE OpenMutex(
DWORDfdwAccess,
BOOLbInheritHandle,
PCTSTRpszName);
By calling a wait function and passing a handle to the mutex object that protects the resource, the thread can gain access to the shared resource. Internally, wait for the function to check the thread ID to see if it is 0 (the mutex object sends a notification signal ).
If the thread ID is 0, the thread ID is set to the ID of the calling thread, the recursive counter is set to 1, and the calling thread remains schedulable.
If the wait function finds that the ID is not 0 (the notification signal of the mutex object is not sent), The Calling thread enters the waiting state. The system will remember this situation, and when the I d of the mutex object is reset to 0, set the thread ID to the I D of the waiting thread, and set the recursive counter to 1, and allow the waiting thread to become a schedulable thread again. As in all cases, checks and modifications to mutually exclusive kernel objects are performed through atomic operations.
Exception rules
For mutex objects, there is a special exception in the notified and not notified rules of normal kernel objects.
For example, a thread tries to wait for an unnotified mutex object. In this case, the thread is usually placed in the waiting state.HoweverThe system needs to check whether the thread I d that is trying to obtain the mutex object is the same as the thread I D recorded in the mutex object. If the two threads have the same I D, even if the mutex object is not notified, the system allows the thread to remain schedulable. We do not consider this "exception" behavior feature to be applicable to other kernel objects anywhere in the system. Every time a thread successfully waits for a mutex object, the recursive counter of this object increments. To make the recursive counter value greater than 1, the only method is that the thread waits for the same mutex object multiple times to use this exception rule.
Once the thread successfully waits for a mutex object, the thread will know that it has exclusive access to protected resources. Any other thread that tries to access the resource (by waiting for the same mutex object) is put in the waiting state. When a thread that currently has access to resources no longer needs access, it must callReleaseMutexFunction to release the mutex:
BOOL ReleaseMutex(HANDLE hMutex);
This function reduces the recursive counter of an object by 1. If the thread successfully waits for a mutex object multiple times, the ReleaseMutex function must be called as many times before the recursive counter of the mutex object changes to 0. When the recursive counter reaches 0, the thread ID is also set to 0, and the object changes to the notified State.
When this object changes to the notified State, the system needs to check whether any thread is waiting for the mutex object. If yes, the system selects one of the waiting threads Based on the fairness principle and grants it the ownership of the mutex object. Of course, this means that thread I D is set to the ID of the selected thread and the recursive counter is set to 1. If no other thread is waiting for the mutex object, the mutex object remains notified. In this way, the mutex object can be obtained immediately after the next thread of the mutex object.
Release Problems
The mutex object is different from all other kernel objects because the mutex object has aThread ownership. Among other kernel objects introduced in this chapter, no one can remember which thread successfully waits for the object. Only mutex objects can keep track of the object. The thread ownership concept of a mutex object is the reason why the mutex object has special exception rules. This exception rule allows the thread to obtain the mutex object even though it does not send a notification.
This exception rule applies not onlyObtainThe thread of the mutex object.ReleaseThe thread of the mutex object. When a thread calls the ReleaseMutex function, it needs to check whether the call thread ID matches the thread ID in the mutex object. If the two ids match, the recursive counter will decrease as described above. If the IDs of the two threads do not match, the ReleaseMutex function returns the fa lse (indicating failure) to the caller without any operation. Call GetLastError to return ERROR_NOT_OWNER (trying to release mutex objects not owned by the caller ).
Therefore, if the thread that owns the mutex object stops running (using the ExitThread, TerminateThread, ExitProcess, or TerminateProcess functions) before the mutex object is released ), what will happen to the mutex object and other threads waiting for the mutex object? The answer is that the system regards the mutex object as being abandoned-the thread with the mutex object will never release it because the thread has terminated the operation.
Because the system keeps track of all mutex objects and thread kernel objects, it can accurately know when mutex objects are discarded. When a mutex object is abandoned, the system automatically sets the I D of the mutex object to 0 and Its Recursive counter to 0. Then, the system needs to check whether any thread is waiting for the mutex. If yes, the system selects a waiting thread fairly, sets I d to the I D of the selected thread, and sets the recursive counter to 1. At the same time, the selected thread becomes a schedulable thread.
This is the same as the preceding situation. The difference is that the wait function does not return the usual wa I T _ OBJECT_0 value to the thread. On the contrary, wait for the function to return a specialWAIT_ABANDONEDValue. This special return value (only applicable to mutex objects) is used to indicate that the mutex object waiting by the thread is owned by another thread, the other thread stops running before it completes the use of shared resources. (FangSH Note: it is like being abandoned. Some wait, some give up halfway. Results are not used.) This is not the best scenario. The newly scheduled thread does not know the current status of the resource, and the resource may have been completely destroyed. In this case, you must decide what the application should do.
In the actual running environment, most applications never explicitly check the return value of WAIT_ABANDONED, because the thread is rarely just terminated (another example is provided in the above section, explain why the TerminateThread function should never be called ).
Comparison between mutex objects and key code segments
In terms of waiting for thread scheduling, mutex objects share the same characteristics with key code segments. However, they are different in other attributes. Table.
Table 9-1 Comparison Between mutex objects and key code segments
Features |
Mutex object |
Key code segment |
Running Speed |
Slow |
Fast |
Whether it can be used across process boundaries |
Yes |
No |
Statement |
HANDLE hctx; |
CRITICAL_SECTION cs; |
Initialization |
Hctx = CreateMutex (NULL, FALSE, NULL ); |
InitializeCriticalSection (& es ); |
Clear |
CloseHandle (HGP ); |
DeleteCriticalSection (& cs ); |
Unlimited waiting |
WaitForSingleObject (HGP, INFINITE ); |
EnterCriticalSection (& cs ); |
0 wait |
WaitForSingleObjectTry (hctx, 0 ); |
EnterCriticalSection (& cs ); |
Arbitrary waiting |
WaitForSingleObject (HGP, dw Milliseconds ); |
No |
Release |
ReleaseMutex (HMT ); |
LeaveCriticalSection (& cs ); |
Can I wait for other kernel objects? |
Yes (using WaitForMultipleObjec ts or similar functions) |
No |
FangSH 2011-01-04