C ++ collection -- multithreading: Atomic operations solve thread conflicts, -- Multithreading
C ++ collection-multithreading: Atomic operations solve thread conflicts
Preface
Operations on global variables in multiple threads usually lead to thread conflicts. To solve thread conflicts, atomic operations are introduced.
Body 1. Thread conflict
# Include <stdio. h> # include <stdlib. h> # include <process. h> # include <Windows. h> int g_count = 0; void count (void * p) {Sleep (100 ); // do some work // each thread adds g_count to 1 for 10 times (int I = 0; I <10; I ++) {g_count ++ ;} sleep (100); // do some work} int main (void) {printf ("******* multi-thread global variable access demonstration ***** by David ***** \ n "); // create 10 threads HANDLE handles [10]; for (int I = 0; I <10; I ++) {for (int j = 0; j <10; j ++) {handles [j] = _ beginthread (count, 0, NULL);} WaitForMultipleObjects (10, handles, 1, INFINITE ); printf ("% d time g_count = % d \ n", I, g_count); // reset g_count = 0;} getchar (); return 0 ;}
Run
In theory, the final result of g_count should be 100, but this is not the case. Not only is the result not necessarily 100, but the results may be different each time. The reason is that when multiple threads access the same global variable, especially when performing modification operations, it may cause a conflict. Explanation:
Set breakpoints and view Disassembly
G_count ++; operations are divided into three steps:
1. Move g_count content from memory to register eax
2. Add register eax to 1
3. Move the content in register eax to the address of memory g_count
After three steps, the value of g_count is successfully increased by 1.
The time slice executed by the cpu contains multiple commands, which are not interrupted during execution. However, if an operation contains multiple commands, the operation may be interrupted. G_count ++.
The premise that g_count is successfully added to 100 is that each addition of 1 is based on the previous addition of 1. That is to say, if the last addition of 1 is interrupted, this addition of 1 will not be able to achieve the cumulative effect of the previous addition of 1. Naturally, most of the final results are less than 100.
2. Atomic operations
The so-called atomic operation is an operation that will not be interrupted by the thread scheduling mechanism. Once an operation starts, it must be executed until the end of the operation. An atomic operation can be a step or multiple operation steps. However, the sequence of the atomic operation cannot be disrupted, or the atomic operation can only be executed. Atomic operations are generally implemented by underlying assembly.
Many atomic operation functions are provided in the header file winnt. h. They use the auto-locking method to ensure the atomicity of the operation, such as the auto-increment operation.
InterlockedIncrement,
Function prototype
LONG CDECL_NON_WVMPURE InterlockedIncrement (
_ Inout _ Interlocked_operand _ LONG volatile * Addend
);
For other operations, check the header file.
Using this function, we modify the thread function count. The modification is simple. You only need to change g_count ++ to InterlockedIncrement (LONG) & g_count.
Run the following command:
Obviously, under the atomic operation, we can certainly get the correct result.
Contents of this column
Directory of all contents