Multi-threaded Face Question series (5): Classic thread sync key segment CS

Source: Internet
Author: User

The previous article proposed a classic multi-threaded synchronization Mutex problem, this article will use the key section critical_section to try to solve this 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
  1. #include <stdio.h>
  2. #include <process.h>
  3. #include <windows.h>
  4. Long G_nnum;
  5. unsigned int __stdcall fun (void *ppm);
  6. const int thread_num = 10;
  7. Key segment Variable Declaration
  8. critical_section G_csthreadparameter, G_csthreadcode;
  9. int main ()
  10. {
  11. printf ("Classic thread sync critical section \ n");
  12. printf ("-by Morewindows (http://blog.csdn.net/MoreWindows)--\n\n");
  13. //Critical segment initialization
  14. InitializeCriticalSection (&g_csthreadparameter);
  15. InitializeCriticalSection (&g_csthreadcode);
  16. HANDLE Handle[thread_num];
  17. G_nnum = 0;
  18. int i = 0;
  19. While (i < thread_num)
  20. {
  21. EnterCriticalSection (&g_csthreadparameter); //Enter the sub-line program number key area
  22. Handle[i] = (handle) _beginthreadex (NULL, 0, fun, &i, 0, NULL);
  23. ++i;
  24. }
  25. WaitForMultipleObjects (Thread_num, handle, TRUE, INFINITE);
  26. DeleteCriticalSection (&g_csthreadcode);
  27. DeleteCriticalSection (&g_csthreadparameter);
  28. return 0;
  29. }
  30. unsigned int __stdcall fun (void *ppm)
  31. {
  32. int nthreadnum = * (int *) PPM;
  33. LeaveCriticalSection (&g_csthreadparameter); //Leave the sub-line program number key area
  34. Sleep (50); //some work should
  35. EnterCriticalSection (&g_csthreadcode); //Enter each sub-thread mutex area
  36. g_nnum++;
  37. Sleep (0); //some work should
  38. printf ("Thread number%d global resource value is%d\n", Nthreadnum, G_nnum);
  39. LeaveCriticalSection (&g_csthreadcode); //Leave each sub-thread mutex area
  40. return 0;
  41. }

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 namely EnterCriticalSection (&g_csthreadparameter); Enter the sub-line program number key area of 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. The following is a key segment initialization function that fits 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 article describes the use of event events to solve this classic thread synchronization problem.

Multi-threaded Face Question series (5): Classic thread sync key segment CS

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.