On a "second-kill multi-threaded fourth a classic multi-threaded synchronization problem" proposed a classic multi-threaded synchronization Mutex problem, this article will use the key section critical_section to try to solve the problem.
This article first introduces how to use the key section, and then the deep analysis of the key section of the implementation mechanism and principle.
The key section critical_section altogether has four functions, the use is very convenient. Here are the prototypes and instructions for using these four functions.
function function: Initialize
Function Prototypes:
void InitializeCriticalSection (lpcritical_sectionlpcriticalsection);
Function Description: The key segment variable must be initialized before it is defined.
function function: Destroy
Function Prototypes:
void DeleteCriticalSection (lpcritical_sectionlpcriticalsection);
Function Description: After use, remember to destroy.
function function: Enter key area
Function Prototypes:
void EnterCriticalSection (lpcritical_sectionlpcriticalsection);
Function Description: The system ensures that each thread is mutually exclusive into the critical area.
function function: Off-switch key area
Function Prototypes:
void LeaveCriticalSection (lpcritical_sectionlpcriticalsection);
Then set two key areas in the classic multithreading problem. One is when the main thread increments the child line program number, and the other is the mutually exclusive access output global resource for each child thread. See the code:
[CPP]View PlainCopy
- #include <stdio.h>
- #include <process.h>
- #include <windows.h>
- Long G_nnum;
- unsigned int __stdcall fun (void *ppm);
- const int thread_num = 10;
- Key segment Variable Declaration
- critical_section G_csthreadparameter, G_csthreadcode;
- int main ()
- {
- printf ("Classic thread sync critical section \ n");
- printf ("-by Morewindows (http://blog.csdn.net/MoreWindows)--\n\n");
- //Critical segment initialization
- InitializeCriticalSection (&g_csthreadparameter);
- InitializeCriticalSection (&g_csthreadcode);
- HANDLE Handle[thread_num];
- G_nnum = 0;
- int i = 0;
- While (i < thread_num)
- {
- EnterCriticalSection (&g_csthreadparameter); //Enter the sub-line program number key area
- Handle[i] = (handle) _beginthreadex (NULL, 0, fun, &i, 0, NULL);
- ++i;
- }
- WaitForMultipleObjects (Thread_num, handle, TRUE, INFINITE);
- DeleteCriticalSection (&g_csthreadcode);
- DeleteCriticalSection (&g_csthreadparameter);
- return 0;
- }
- unsigned int __stdcall fun (void *ppm)
- {
- int nthreadnum = * (int *) PPM;
- LeaveCriticalSection (&g_csthreadparameter); //Leave the sub-line program number key area
- Sleep (50); //some work should
- EnterCriticalSection (&g_csthreadcode); //Enter each sub-thread mutex area
- g_nnum++;
- Sleep (0); //some work should
- printf ("Thread number%d global resource value is%d\n", Nthreadnum, G_nnum);
- LeaveCriticalSection (&g_csthreadcode); //Leave each sub-thread mutex area
- return 0;
- }
Running results such as:
As you can see, each child thread is already able to access and output global resources mutually exclusive, but the synchronization between the main thread and the child thread is still a bit problematic.
Why is that?
The most straightforward way to solve this puzzle is to first add a breakpoint to the program to see how the program runs. The breakpoint is disposed as follows:
Then press F5 to debug, normally these two breakpoints should be executed in turn, but the actual debugging found that this is not the case, the main thread can be multiple times through the first breakpoint
EnterCriticalSection (&g_csthreadparameter);//Enter the sub-line program number key area
This statement. This means that the mainline Cheng Nen multiple times into this critical area! After finding the reason why the main thread and the child thread failed to synchronize, let's analyze the reasons for the reason below. ^_^
Find the definition of key section critical_section first, it is defined as rtl_critical_section in WinBase.h. and rtl_critical_section in WinNT.h that it is actually a struct:
typedef struct _RTL_CRITICAL_SECTION {
Prtl_critical_section_debugdebuginfo;
Longlockcount;
Longrecursioncount;
Handleowningthread; From the thread ' s Clientid->uniquethread
Handlelocksemaphore;
Dwordspincount;
} rtl_critical_section, *prtl_critical_section;
The explanations for each parameter are as follows:
First parameter: prtl_critical_section_debugdebuginfo;
For debugging purposes.
Second parameter: Longlockcount;
Initializing to -1,n indicates that there are N threads waiting.
A third parameter: Longrecursioncount;
Indicates that the owning thread for this critical segment has a critical number of times for this resource, beginning with 0.
Fourth parameter: Handleowningthread;
That is, the thread handle of the critical segment, which Microsoft notes as--from the thread ' s Clientid->uniquethread
Fifth parameter: Handlelocksemaphore;
is actually a self-resetting event.
Sixth parameter: Dwordspincount;
Rotation lock settings, single CPU under ignore
It is up to this structure to know that the critical segment will record the thread handle that holds the critical segment and that the critical segment has a "thread ownership" concept . In fact, it uses the fourth parameter OwningThread to record the thread handle that is allowed to enter the critical area, and if the thread enters again, EnterCriticalSection () The third parameter, Recursioncount, is updated to record the number of times the thread has entered and immediately returns to let the thread enter. Other threads calling EnterCriticalSection () are switched to the wait state, and once the thread ownership of the thread calls LeaveCriticalSection () brings it into the number of 0 o'clock, The system automatically updates the critical segment and returns the waiting thread back to the scheduled state.
Therefore, the key section can be likened to the hotel's room card, call EnterCriticalSection () to apply for a room card, get the room card, of course, you can come in and out of the room, before you call LeaveCriticalSection () hand over the room card, It is natural for others to be unable to enter the room.
Back to this classic thread synchronization problem, the main course is due to having "thread ownership" that is the room card, so it can repeatedly enter the critical code area, causing the child thread to receive parameters before the main thread has modified this parameter. So the critical segment can be used for mutual exclusion between threads, but not for synchronization.
In addition, because of the overhead of switching threads to the wait state, in order to improve the performance of critical segments, Microsoft merges rotation locks into critical segments so that entercriticalsection () loops through a rotation lock for a period of time before switching threads to a wait state. Here is the key segment initialization function with the rotation lock
function function: Initialize key segment and set number of rotations
Function Prototypes:
Boolinitializecriticalsectionandspincount (
Lpcritical_sectionlpcriticalsection,
Dworddwspincount);
Function Description: The number of rotations is generally set to 4000.
function function: Change the number of rotations of a key segment
Function Prototypes:
Dwordsetcriticalsectionspincount (
Lpcritical_sectionlpcriticalsection,
Dworddwspincount);
The eighth chapter of the fifth edition of Windows core programming recommends the use of rotary locks while using critical segments, which helps improve performance. It is important to note that setting a rotation lock is not valid if the host has only one processor. Threads that fail to enter critical areas are always switched to the wait state by the system.
Finally summarize the following key sections:
1. Key segments are initialized, destroyed, entered, and left in the critical area of four functions.
2. A critical segment resolves a thread's mutex problem, but because it has "thread ownership", the synchronization problem cannot be resolved.
3. It is recommended that the critical section be used in conjunction with the rotary lock.
The next "second-round multi-threaded sixth" Classic thread synchronization events event will introduce the use of event events to solve this classic thread synchronization problem.
Reprint please indicate source, original address: http://blog.csdn.net/morewindows/article/details/7442639
Classic thread sync critical segment CS