One : summary
In the project, we often encounter the problem of multi thread operation sharing data , The common processing method is to lock the shared data , If multi-threaded operations share variables, the same approach is used .
Why lock shared variables or use atomic operations ? For example, when two threads operate the same variable , A thread may be temporarily suspended by the kernel during execution , This is thread switching , When the kernel switches to the thread again , Previous data may have been modified , Atomic operation cannot be guaranteed .
C++11 Provides atomic classes and methods atomic, It ensures the atomicity of variables by multithreading , Compared with locking mechanism mutex.lock(),mutex.unlock(), Performance has been improved several times .
Required header file <atomic>
Two : error code
// global variable int g_num = 0; void fun() { for (int i = 0; i < 10000000; i++) {
g_num++; } return ; } int main() { // Create thread 1 thread t1(fun); // Create thread 2 thread
t2(fun); t1.join(); t2.join(); cout << g_num << endl; getchar(); return 1; }
The result should be output 20000000, The actual results are different every time , Always less than this value , It is because multithreading operates on the same variable without ensuring atomicity .
Three : Lock code
// global variable int g_num = 0; mutex m_mutex; void fun() { for (int i = 0; i <
10000000; i++) { m_mutex.lock(); g_num++; m_mutex.unlock(); } return ; } int
main() { // Gets the current millisecond timestamp typedef chrono::time_point<chrono::system_clock,
chrono::milliseconds> microClock_type; microClock_type tp1 =
chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time1 = tp1.time_since_epoch().count(); // Create thread thread t1(fun); thread
t2(fun); t1.join(); t2.join(); cout << " total :" << g_num << endl; // Gets the current millisecond timestamp
microClock_type tp2 =
chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time2 = tp2.time_since_epoch().count(); cout << " time consuming :" << time2 -
time1 << "ms" << endl; getchar(); return 1; }
results of enforcement : The output of multiple tests is 20000000, Time consuming 3.8s about
Four :atomic Atomic operation code
// global variable atomic<int> g_num = 0; void fun() { for (int i = 0; i < 10000000; i++)
{ g_num++; } return ; } int main() { // Gets the current millisecond timestamp typedef
chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
microClock_type tp1 =
chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time1 = tp1.time_since_epoch().count(); // Create thread thread t1(fun); thread
t2(fun); t1.join(); t2.join(); cout << " total :" << g_num << endl; // Gets the current millisecond timestamp
microClock_type tp2 =
chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time2 = tp2.time_since_epoch().count(); cout << " time consuming :" << time2 -
time1 << "ms" << endl; getchar(); return 1; }
results of enforcement : The output of multiple tests is 20000000, Time consuming 1.3s about
Five : summary
c++11 Atomic class of atomic Compared with the lock mechanism, the performance is better 2~3 Double increase , For shared variables that can use atomic type, do not use locking mechanism .
Technology
Daily Recommendation