During this period of time, I have been working on Windows project development. Recently I spent some time turning over the book and summarizing the commonly used Thread Synchronization Methods in Windows.
I. Thread Synchronization-SendMessage ()
1. SendMessage () is a simple and convenient method for data synchronization between windows and worker threads.
2. After the worker thread prepares the data, it can call SendMessage () to send the message to the specified window. Then, the sending thread will be blocked until SendMessage () returns.
LRESULT SendMessage (
HWND hWnd, // target window handle
UINT Msg, // message to be sent
WPARAM wParam, // The first message Parameter
LPARAM lParam // The second Message Parameter
);
Note: PostMessage with similar functions is not blocked. messages are sent to the Message Queue of the UI main thread for direct return.
Ii. Thread Synchronization-Critical Section)
1. Only one thread is allowed to gain access to a data zone at a time in the critical section, so that only one thread can enter the critical section at a time ).
2. Critical zones are very suitable for accessing data in a process because they are fast.
3. The critical section object is not a kernel object. It cannot be managed by low-level components of the operating system and cannot be operated by handles.
4. Create a critical section in the process, that is, allocate a CRITICAL_SECTION data structure in the process. The distribution of the structure of the critical section must be global, so that different threads of the process can access it.
5. before using the thread for synchronization in the critical section, you must call InitializeCriticalSection to initialize the critical section. Before releasing resources, you only need to initialize the section once.
6. call VOID EnterCriticalSection () to enter the critical section. If an object in the critical section is occupied by another thread, the thread will be congested and sleep until the thread that occupies the object in the critical section releases the object in the critical section. Before it is awakened, the system does not allocate CPU to it.
7. Call VOID TryEnterCriticalSection () to enter the critical section. If an object in the critical section is occupied by another thread, FALSE is returned. The thread does not enter the sleep state and continues execution.
8. Call LeaveCriticalSection () to leave the critical section. When a thread with the critical section ownership calls LeaveCriticalSection to give up ownership, the system only wakes up one thread in the waiting state and gives it ownership. Other threads continue to sleep.
9. note: EnterCriticalSection () and LeaveCriticalSection () must be called in pairs. When a thread occupying the critical section calls EnterCriticalSection () multiple times, the reference count of the critical section object is increased by one, if you want to discard the critical area ownership, you must call the same number of LeaveCriticalSection ()
10. Call DeleteCriticalSection to release critical zone resources.
Typedef struct _ RTL_CRITICAL_SECTION
{
Long LockCount;
Long RecursionCount;
HANDLE oWningThread; // from the thread's ClientId-> UniqueThread
HANDLE LockSemaphore;
DWORD SpinCount;
} PTL_CRITICAL_SECTION, * PRTL_CRITICAL_SECTION;
Typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION
Typedef RTL_CRITICAL_SECTION CRITICAL_SECTION
VOID InitializeCriticalSection (maid Section)
VOID EnterCriticalSection (maid Section)
BOOL TryEnterCriticalSection (maid Section)
VOID LeaveCriticalSection (maid Section)
VOID DeleteCriticalSection (maid Section)
Sample Code:
TryEnterCriticalSection (& critical_section)
TODO: synchronize data here
LeaveCriticalSection (& critical_section)
If (TryEnterCriticalSection (& critical_section ))
{
TODO: synchronize data here
LeaveCriticalSection (& critical_section );
}
Iii. Thread Synchronization-Kernel Object
1. Applicable to data synchronization between threads of multiple processes.
2. It can also implement thread synchronization in a single process, but the efficiency is much lower than that of using the critical section.
4. The following kernel objects can be used to synchronize threads:
Process, Processes
Thread, Threads
Files, Files
Console input
File change notifications
Mutexes
Semaphores, Semaphores
Events (automatic resetting Events and manual resetting Events), Events
Optional timers (only used for Window NT4 or higher), Waitable timers
Jobs
5. Among all kernel objects, the event kernel object is the most basic object.
6. Use the CreateEvent () function to create an event Kernel Object
7. Use the OpenEvent () function to open the event Kernel Object
8. CloseHandle () to release kernel objects
9. Use SetEvent () to change the event status to notified:
10. When using the ResetEvent () function, you can change this event to the "not notified" status:
11. The WaitForSingleObject () function is used in the worker's current process to detect the signal status of the hHandle event.
Function Description: Creates or opens a named or unknown event object.
Function prototype:
HANDLE CreateEvent (
LPSECURITY_ATTRIBUTES lpEventAttributes, // Security Attribute
BOOL bManualReset, // reset mode
BOOL bInitialState, // initial state
Lptstr lpName // Object Name
);
DWORD WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds );
The hHandle parameter is the handle of an event, and the second parameter dwMilliseconds is the time interval. If the time is in the signal status, return WAIT_OBJECT_0. If the time exceeds the dwMilliseconds value but the time event is still in the non-Signal status, return WAIT_TIMEOUT.
However, if the dwMilliseconds parameter is INFINITE, the function will not return until the corresponding time event changes to a signal state. Otherwise, it will wait until the WaitForSingleObject returns directly before executing the subsequent code.
Sample Code:
Manual reset event usage: When SetEvent is set for the master thread, worker thread A and worker thread B start to work at the same time. For example, you can perform parallel read operations on A piece of data at the same time.
Master thread:
HANDLE hEvent; // global
HEvent = CreateEvent (NULL, TRUE, FALSE, NULL); // create an event object, telling the system to create a manual reset event object
SetEvent (hEvent); // control the worker thread MyThreadA/MyThreadB to start working.
Worker threads A and B:
UINT MyThreadA (LPVOID pParam)
{
For (;;)
{
WaitForSingleObject (hEvent, INFINITE );
// The worker thread does something
}
Return 0;
}
UINT MyThreadB (LPVOID pParam)
{
For (;;)
{
WaitForSingleObject (hEvent, INFINITE );
// The worker thread does something
}
Return 0;
}
Auto-Reset event usage: after the main control thread sets the SetEvent, the worker thread A and worker thread B start to work, and the other will continue to wait, it does not start until one operation completes another working thread. for example, if multiple threads write a piece of data, they must be serialized.
Master thread:
HANDLE hEvent; // global
HEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // create an event object, telling the system to create an automatic reset event object
SetEvent (hEvent); // control the worker thread MyThreadA/MyThreadB to start working.
Worker threads A and B:
UINT MyThreadA (LPVOID pParam)
{
For (;;)
{
WaitForSingleObject (hEvent, INFINITE );
// Do something here
SetEvent (hEvent );
}
Return 0;
}
UINT MyThreadB (LPVOID pParam)
{
For (;;)
{
WaitForSingleObject (hEvent, INFINITE );
// Do something here
SetEvent (hEvent );
}
Return 0;
}