Purpose: ensure that a thread exclusively accesses a resource.
Usage:
For example, multiple threads need to perform read/write operations on the same memory. The procedure is as follows:
Handle hmutex = createmutex (null, false, null); // create a mutex
T read ()
{
Waitforsingleobject (hmutex, infinite );
// Read the buffer
Releasemutex (hmutex );
}
Void write (t data)
{
Waitforsingleobject (hmutex, infinite );
// Write the buffer
Releasemutex ();
}
Understanding:
Create a mutex for thread synchronization. The mutex object contains a count, thread ID, and a recursive count. The thread ID identifies the system thread that currently occupies the mutex. The recursive count identifies the number of times this thread occupies the mutex. The second parameter of createmutex specifies the status when the mutex kernel object is initially created (true is not triggered, false is triggered). For other parameters, see msdn. Assume that there are two threads, one for operation and the other for read operation.
Assume that the write thread executes the write operation for the first time, calls the wait function waitforsingleobject, and passes in the mutex handle. Internally, wait for the function to check whether the mutex thread ID is 0 (the mutex is triggered ). If the value is 0, the function sets the thread ID as the thread ID of the entry, sets the recursive count to 1, and then allows the calling thread to continue running. It must be noted that the waitforsingleobject function enables a thread to voluntarily enter the waiting state until the specified kernel object is triggered. However, if the corresponding kernel object is already triggered when the thread calls a waiting function, the thread will not enter the waiting state. That is to say, the waiting function waits for the instantaneous changes of the kernel object state (from not triggered to triggered), rather than waiting for the changed state. If the mutex is created in the preceding example, the second parameter is set to true, that is, the initial status is not triggered, so unless we call a function explicitly to make the kernel state change to the trigger state, the read/write thread will never capture changes in the kernel state, so that there will be a situation of waiting forever.
Back to the previous situation, the write thread is executing the write operation. The thread ID of the mutex Kernel Object records the thread ID that currently occupies the mutex. At this point, the read thread executes the read operation and calls the wait function. Wait for the function to check the mutex thread ID. If the ID is not 0, the read thread enters the waiting state. Call releasemutex after the write thread completes the write operation. Internally, this function reduces the recursive count of the mutex kernel object by 1. When the recursive count is changed to 0, the function also sets the thread ID to 0, this triggers the kernel object. When an object is triggered, the system checks whether other threads are waiting for the mutex. If the system selects a waiting thread fairly, give the ownership of the mutex. Similarly, the kernel object sets the thread ID to the thread ID that occupies the mutex and the recursive count to 1. In the preceding example, the read thread has the opportunity to read the memory. If no thread waits, the mutex will remain in the trigger State, so that the next thread waiting for it can immediately enter the mutex region.
Note:
(1) assuming that the thread tries to wait for an untriggered kernel object, the thread usually enters the waiting state. But this is not necessarily the case for mutex kernel objects. If the thread ID is the same as the internal thread ID of the mutex, the thread will remain in the schedulable State, even if the mutex is not triggered. Simply put, waitforsingleobject is called when the current thread has a mutex. This is the only way for Recursive counting to be greater than 1. If you have successfully waited for the mutex for multiple times, you must call the releasemutex function for the corresponding number of times to make the mutex trigger.
(2) If the thread ID is consistent with the internal ID of the mutex, the recursive count is reduced by 1. If they are inconsistent, releasemutex returns false to the caller, indicating that the call fails. If the thread that releases the mutex has been terminated, the system determines that the mutex has been "abandoned ". The system automatically sets the mutex thread ID to 0, the recursive count to 0, and the mutex is in the triggered state.