Many people have incorrect understanding of critical_section and think that critical_section locks resources. In fact, critical_section cannot "Lock" resources and can complete functions, is the code segment for synchronizing different threads. Simply put, after a thread executes the entercritialsection, the information in CS is modified to indicate which thread occupies it. At this time, no resource is "locked ". No matter what resources, other threads are still accessible (of course, the execution result may be incorrect ). However, before this thread executes the leavecriticalsection, if other threads encounter the entercritialsection statement, the thread will be in the waiting state, which is equivalent to being suspended. In this case, it plays a role in protecting shared resources.
Because critical_section plays a role in this way, You must place the statements used to access shared resources in each thread between entercritialsection and leavecriticalsection. This is something that beginners can easily ignore.
Of course, the above is for the same critical_section. If two critical_sections are used, for example:
The first thread has already executed entercriticalsection (& CS) and has not executed leavecriticalsection (& Cs). Then the other thread wants to execute entercriticalsection (& CS2 ), this is acceptable (unless CS2 is occupied by the third thread first ). This is the idea of synchronizing multiple critical_sections.
For example, we have defined a shared resource dwtime [100]. Both threadfunca and threadfuncb perform read and write operations on it. To ensure the integrity of the dwtime [100] operation, that is, if we do not want to write half of the data to be read by another thread, 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 mistakenly think that CS locks dwtime and dwtime is under CS protection. A "natural" idea is that CS and dwtime correspond one by one. This is a big mistake. Dwtime does not correspond to anything, and it can still be accessed by any other thread.
If you write the second thread in the following way, there will be a problem:
DWORD winapi threadfuncb (lpvoid LP)
{
...
// Operate dwtime
...
Return 0;
}
When the thread threadfunca executes entercriticalsection (& CS) and starts to operate dwtime [100], the thread threadfuncb may wake up at any time and start to operate dwtime [100]. In this way, data in dwtime [100] is damaged.
To make critical_section take effect, we must add entercriticalsection (& CS) and leavecriticalsection (& CS) statements to any part of the dwtime access. Therefore, the second thread function must be written as follows:
DWORD winapi threadfuncb (lpvoid LP)
{
Entercriticalsection (& CS );
...
// Operate dwtime
...
Leavecriticalsection (& CS );
Return 0;
}
In this way, when the 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 on dwtime [100] at this time, the value contained in the CS variable will tell the second thread that other threads are occupying CS. Therefore, the entercriticalsection (& CS) Statement of the second thread will not be returned, but will be in the pending status. The entercriticalsection (& CS) Statement of the second thread does not return until the first thread executes leavecriticalsection (& CS) and continues to perform the following operations.
This process is actually implemented by limiting only one function to enter the criticalsection variable. Simply put, for the same critical_section, when a thread executes entercriticalsection but does not execute leavecriticalsection, no other thread can fully execute entercriticalsection and has to wait.
Once again, no resource is "locked". The "critical_section" is not for resources, but for code segments between different threads! We can use it to "Lock" the so-called resources because the entercriticalsection and leavecriticalsection statements are added to any access to shared resources, so that only one thread's code segment can access the shared resource at a 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 can help you understand the things of 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 thread sleep for a total of 1000 seconds! Obviously, it does not implement "conscious" protection for any resources, while the second thread needs to access the resource index. However, because the first thread occupies CS, there has been no leave, as a result, the second thread has to be mounted for 1000 seconds ......
The second thread is really poor...
This should be a clear explanation of the problem. You will see that the second thread starts to execute the Index = 2 statement after 1000 seconds.
That is to say, critical_section does not really care about the specific shared resources you are concerned about. It only works according to its own rules ~