CRITICAL_SECTION details

When I wrote an independent module in the project, I found that the multi-threading used was wrong. The inspection found that it was a problem of thread locking. Learn about it.

Article source: http://blog.csdn.net/greston/article/details/8162984

Many people's understanding of CRITICAL_SECTION is wrong. They think that CRITICAL_SECTION locks resources. In fact, CRITICAL_SECTION cannot "lock" resources. The function it can complete is to synchronize code segments of different threads. Simply put, when a thread executes EnterCritialSection, the information in cs is modified to indicate which thread occupies it. At this time, no resources are "locked". No matter what resource, other threads can still access it (of course, the result of execution may be wrong). However, before the thread has not executed LeaveCriticalSection, if other threads encounter the EnterCritialSection statement, they will be in a waiting state, which is equivalent to the thread being suspended. In this case, it plays a role in protecting shared resources. 

      It is also because CRITICAL_SECTION plays a role in this way, so the statements that access shared resources in each thread must be placed between EnterCritialSection and LeaveCriticalSection. This is something that beginners can easily overlook. 
Of course, all of the above are for the same CRITICAL_SECTION. If two CRITICAL_SECTIONs are used, for example: 
the first thread has executed EnterCriticalSection(&cs) and has not executed LeaveCriticalSection(&cs), then another thread wants to execute EnterCriticalSection(&cs2), this situation is OK ( unless cs2 is already preempted by a third thread). This is the idea of ​​multiple CRITICAL_SECTION synchronization.

       For example, we define a shared resource dwTime[100], and both threads ThreadFuncA and ThreadFuncB read and write to it. When we want to ensure the operational integrity of dwTime[100], that is, we do not want half of the data written to be read by another thread, then use CRITICAL_SECTION for thread synchronization as follows: 
The first thread function: 
DWORD WINAPI ThreadFuncA(LPVOID lp ) 

EnterCriticalSection(&cs); 
... 
// Operate dwTime 
... 
LeaveCriticalSection(&cs); 
return 0; 

After writing this function, many beginners will mistakenly think that cs locks dwTime at this time, dwTime is under the protection of cs. A "natural" idea is that cs and dwTime correspond one by one. If you think so, you are wrong. dwTime doesn't correspond to anything, it's still accessible by any other thread.

There will be a problem if you write the second thread like this: 
DWORD WINAPI ThreadFuncB(LPVOID lp) 

... 
// operation dwTime 
... 
return 0; 

When thread ThreadFuncA executes EnterCriticalSection(&cs) , and start to operate dwTime[100], the thread ThreadFuncB may wake up at any time and also start to operate dwTime[100], so the data in dwTime[100] is destroyed. 
      For CRITICAL_SECTION to work, we must add EnterCriticalSection(&cs) and LeaveCriticalSection(&cs) statements anywhere we access dwTime. Therefore, the second thread function must be written as follows: 
DWORD WINAPI ThreadFuncB(LPVOID lp) 

EnterCriticalSection(&cs); 
... 
// operation dwTime 
... 
LeaveCriticalSection(&cs); 
return 0; 

       Thus, when thread ThreadFuncB wakes up, the first statement it encounters is EnterCriticalSection(&cs), which will access the cs variable. If the first thread is still operating dwTime[100] at this time, the value contained in the cs variable will tell the second thread that another thread has occupied cs. Therefore, the EnterCriticalSection(&cs) statement of the second thread will not return, but will be in a pending state. Until the first thread executes LeaveCriticalSection(&cs), the second thread's EnterCriticalSection(&cs) statement will not return and continue with the following operations. 
        This process actually achieves code segment synchronization by restricting one and only one function into the CriticalSection variable. Simply put, for the same CRITICAL_SECTION, when a thread executes EnterCriticalSection but does not execute LeaveCriticalSection, any other thread cannot fully execute EnterCriticalSection and has to wait. 
Again, no resources are "locked", CRITICAL_SECTION is not for resources, but for code segments between different threads! We can use it for so-called "locking" of resources, in fact, because we have added EnterCriticalSection and LeaveCriticalSection statements wherever we access shared resources, so that only one thread's code segment can access the shared resources at the same time ( Other code segments that want to access the resource have to wait). 
If there are two CRITICAL_SECTIONs, and so on.

Another extreme example to help you understand CRITICAL_SECTION: 
the first thread function: 
DWORD WINAPI ThreadFuncA(LPVOID lp) 

EnterCriticalSection(&cs); 
for(int i=0;i <1000;i++) 
Sleep( 1000); 
LeaveCriticalSection(&cs); 
return 0; 


The second thread function: 
DWORD WINAPI ThreadFuncB(LPVOID lp) 

EnterCriticalSection(&cs); 
index=2; 
LeaveCriticalSection(&cs); 
return 0; 

       In this case, the first A total of 1000 seconds of Sleep in the middle of a thread! It obviously does not "consciously" protect any resources; and the second thread wants to access the resource index, but because the first thread occupies cs, there is no Leave all the time, so the second thread has to board 1000 seconds... 
Second thread, what a pity. .
This should be very telling, you will see that the second thread starts executing the statement index=2 after 1000 seconds. 
In other words, CRITICAL_SECTION doesn't actually care about the specific shared resources you care about, it only acts according to its own rules~

Guess you like

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