Synchronization of windows thread and kernel object

Synchronization of windows thread and kernel object

Notified/Not Notified Status

When the process is running, the process kernel object is in the unnotified state, and when the process terminates, it becomes the notified state. The process kernel object is a boolean value that is initialized to FA LSE (not notified state) when the object is created. When the process terminates, the operating system automatically changes the boolean value of the corresponding object to TRUE, indicating that the object has been notified. Like process kernel objects, thread kernel objects can be in a notified or unnotified state.

The following kernel objects can be in a notified or unnotified state:
■ Processes ■ File Modification Notifications
■ Threads ■ Events
■ Jobs ■ Waitable Timers

■ file ■ beacon
■ console input ■ mutex object

wait function

A wait function causes a thread to voluntarily enter a wait state until a particular kernel object becomes notified. The most commonly used of these wait functions is WaitForSingleObject :

DWORD WINAPI WaitForSingleObject(
   HANDLE hHandle,
   DWORD  dwMilliseconds
);

When a thread calls this function, the first parameter hObject identifies a kernel object capable of being notified/unnotified (any of the objects listed above are applicable). The second parameter, dw Milliseconds, allows the thread to specify how long it will wait for the object to become notified.

Side Effects of Successful Waiting

For some kernel objects, successfully calling Wait F or S ingle Objects and Wait F or M ultiple Objects will actually change the state of the object. A successful call means that the function finds that the object has been notified and returns a value relative to WA IT_OBJECT_0. If the function returns WA IT_TIMEOUT or WA IT_FA ILED, the call was not successful. If the function call is unsuccessful, the state of the object cannot be changed.
When an object's state changes, I call it a side effect of a successful wait. For example, there is a thread waiting for an auto-clearing event object (described later in this chapter). When the event object becomes notified, the function detects this and returns WA IT_OBJECT_0 to the calling thread. But just before the function returns, the event will be put in the unnotified state, which is a side effect of a successful wait.

The return value of Wait For S ingle Object can indicate why the calling thread becomes schedulable again. If the object the thread is waiting for becomes notified, the return value is WA IT_OBJECT_0. If the set timeout has expired, the return value is WA IT_TIMEOUT. If an incorrect value (such as an invalid handle) is passed to Wait F or S ingl eObject, the return value will be WA IT _ FA ILED .

event kernel object

Among all the kernel objects, the event kernel object is the most basic one. They contain a usage count (like all kernel objects), a boolean indicating whether the event is an auto-reset event or a manually-reset event, and a Boolean value indicating whether the event is notified or unnotified Boolean value for the state.

Events can notify that an operation has completed. There are two different types of event objects. One is a manually reset event, and the other is an automatically reset event. When a manually reset event is notified, all threads waiting for the event become schedulable threads. When an auto-reset event is notified, only one of the threads waiting for the event becomes dispatchable.

Events are used most when one thread performs an initialization operation and then notifies another thread to perform the remaining operations. The event is initialized to the unnotified state, and then, when the thread completes its initialization, it sets the event to the notified state. At this point, another thread that has been waiting for the event finds that the event has been notified, so it becomes a schedulable thread.

The following is the Create Event function, which is used to create the event kernel object:

HANDLE WINAPI CreateEvent(
   LPSECURITY_ATTRIBUTES lpEventAttributes,
   BOOL                  bManualReset,
   BOOL                  bInitialState,
   LPCTSTR               lpName
);

Other operation functions of the event kernel object, OpentEvent, SetEvent, ResetEvent, OpentEvent.

wait timer kernel object

A wait timer is a kernel object that emits its own signal at a certain time or at a specified interval. They are usually used to perform an action at a certain time.
To create a wait timer, just call the CreateWaitableTimer function:

beacon kernel object

Beacon kernel objects are used to count resources. They, like all kernel objects, contain a usage amount, but they also contain two other signed 32-bit values, one for the maximum resource amount and one for the current resource amount. The maximum number of resources is used to identify the maximum number of resources that the beacon can control, and the current number of resources is used to identify the number of resources that can currently be used.

The beacon usage rules are as follows:
• If the number of current resources is greater than 0, a beacon signal is sent.
• If the current resource count is 0, no beacon signal is sent.
• The system never allows the current resource's quantity to be negative.
• The current number of resources must never be greater than the maximum number of resources

The following function is used to create the beacon kernel object:

HANDLE WINAPI CreateSemaphore(
   LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
   LONG                  lInitialCount,
   LONG                  lMaximumCount,
   LPCTSTR               lpName
);

By calling the ReleaseSemaphore function, the thread can increment the current number of resources for the beacon:

BOOL WINAPI ReleaseSemaphore(
   HANDLE hSemaphore,
   LONG   lReleaseCount,
   LPLONG lpPreviousCount
); 

mutex object kernel object

A mutex kernel object ensures that threads have exclusive access to a single resource. In fact, the mutex object is named after it. The mutex object contains a usage count, a thread ID and a recursion counter. Mutex objects behave the same as critical code sections, but mutex objects belong to kernel objects, while critical code sections belong to user mode objects. This means that mutex objects run slower than critical code sections. But it also means that multiple threads in different processes can access a single mutex, and it means that threads can set a timeout value while waiting to access a resource.

The ID is used to identify which thread in the system currently owns the mutex, and the recursion counter is used to indicate the number of times the thread owns the mutex. Mutex objects have many uses and are among the most commonly used kernel objects. Typically, they are used to protect blocks of memory accessed by multiple threads. If multiple threads try to access the memory block at the same time, the data in the memory block may be corrupted. A mutex ensures that any thread accessing a 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 (which is an invalid ID), the mutex object is not owned by any thread, and a notification signal for the mutex object is issued.
• If ID is a non-zero number, then a thread owns the mutex and does not signal the mutex.
• Unlike all other kernel objects, mutexes have special code in the operating system that allows them to violate the normal rules (the exception will be described later).

To use a mutex, a process must first call CreateM utex in order to create the mutex:

HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针
BOOL bInitialOwner, // 初始化互斥对象的所有者
LPCTSTR lpName // 指向互斥对象名的指针
);

Reference for the use of mutex operation functions: Windows Programming – Mutex Mutex Operation Functions

Another process can obtain its own process's handle relative to an existing mutex object by calling OpenMutex:

HANDLE OpenMutex(
DWORD dwDesiredAccess, // access
BOOL bInheritHandle, // inheritance option
LPCTSTR lpName // object name
);

Once a thread successfully waits on a mutex, the thread knows that it has exclusive access to the protected resource. Any other thread attempting to access the resource (by waiting on the same mutex) is placed in a wait state. When the thread that currently has access to the resource no longer needs its access, it must call the ReleaseMutex function to release the mutex:

BOOL WINAPI ReleaseMutex(
HANDLE hMutex
);

This function decrements the object's recursion counter by 1. If a thread successfully waits for a mutex multiple times, the thread must call ReleaseMutex the same number of times before the mutex's recursion counter reaches zero. When the recursion counter reaches 0, the thread ID is also set to 0, and the object becomes notified.

release problem

Mutexes are different from all other kernel objects because mutexes have a concept of "thread ownership". None of the other kernel objects described in this chapter can remember which thread successfully waited for the object, only the mutex object can keep track of this. The notion of thread ownership of a mutex is why a mutex has a special exception rule that enables a thread to acquire the mutex even though it is not notified. This exception rule applies not only to the thread trying to acquire the mutex, but also to the thread trying to release the mutex. When a thread calls the ReleaseMutex function, the function checks to see if the calling thread's ID matches the thread ID in the mutex object. If the two IDs match, the recursion counter is decremented as described earlier. If the IDs of the two threads do not match, the ReleaseMutex function will do nothing but return FA LSE (indicating failure) to the caller. Calling Get Last Error at this point will return ERROR _ NOT _ OWNER (an attempt to release a mutex not owned by the caller). Therefore, if the thread that owns the mutex terminates (using the Exit T hread, Terminate T hread, Exit Process, or Terminate Process functions) before the mutex is released, the mutex and the waiting mutex What will happen to other threads that exploit the object? The answer is that the system will treat the mutex as abandoned - the thread that owns the mutex will never release it because the thread has already terminated. Since the system keeps track of all mutexes and thread kernel objects, it knows exactly when a mutex has been abandoned. When a mutex is abandoned, the system will automatically reset the mutex's ID to 0 and reset its recursion counter to 0. The system then checks to see if any threads are currently waiting on the mutex. If there is, the system will "fairly" select a waiting thread, set the ID to the ID of the selected thread, set the recursion counter to 1, and at the same time, the selected thread becomes a schedulable thread.

Comparison of Mutex Objects and Critical Sections

As far as the scheduling of waiting threads is concerned, a mutex has the same characteristics as a critical section of code. But they differ in other properties.

Mutexes and critical code segments

Thread Synchronization Object Cheat Sheet

Interrelationships between various kernel objects and thread synchronization.

Various kernel object synchronization relationship 1.png

Various kernel object synchronization relationship 2.png

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325473665&siteId=291194637