一:概述
專案中經常用遇到多執行緒操作共享資料問題,常用的處理方式是對共享資料進行加鎖,如果多執行緒操作共享變數也同樣採用這種方式。
為什麼要對共享變數加鎖或使用原子操作?如兩個執行緒操作同一變數過程中,一個執行緒執行過程中可能被核心臨時掛起,這就是執行緒切換,當核心再次切換到該執行緒時,之前的資料可能已被修改,不能保證原子操作。
C++11提供了個原子的類和方法atomic,保證了多執行緒對變數原子性操作,相比加鎖機制mutex.locak(),mutex.unlocak(),效能有幾倍的提升。
所需標頭檔案<atomic>
二:錯誤程式碼
1 //全域性變數 2 int g_num = 0; 3 4 void fun() 5 { 6 for (int i = 0; i < 10000000; i++) 7 { 8 g_num++; 9 } 10 return ; 11 } 12 13 int main() 14 { 15 //建立執行緒1 16 thread t1(fun); 17 //建立執行緒2 18 thread t2(fun); 19 t1.join(); 20 t2.join(); 21 22 cout << g_num << endl; 23 getchar(); 24 return 1; 25 }
應該輸出結果20000000,實際每次結果都不一樣,總是小於該值,正是由於多執行緒操作同一變數而沒有保證原子性導致的。
三:加鎖程式碼
1 //全域性變數 2 int g_num = 0; 3 mutex m_mutex; 4 5 void fun() 6 { 7 for (int i = 0; i < 10000000; i++) 8 { 9 m_mutex.lock(); 10 g_num++; 11 m_mutex.unlock(); 12 } 13 return ; 14 } 15 16 int main() 17 { 18 //獲取當前毫秒時間戳 19 typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type; 20 microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); 21 long long time1 = tp1.time_since_epoch().count(); 22 23 //建立執行緒 24 thread t1(fun); 25 thread t2(fun); 26 t1.join(); 27 t2.join(); 28 29 cout << "總數:" << g_num << endl; 30 31 //獲取當前毫秒時間戳 32 microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); 33 long long time2 = tp2.time_since_epoch().count(); 34 cout << "耗時:" << time2 - time1 << "ms" << endl; 35 36 getchar(); 37 return 1; 38 }
執行結果:多次測試輸出均為20000000,耗時在3.8s左右
四:atomic原子操作程式碼
1 //全域性變數 2 atomic<int> g_num = 0; 3 4 void fun() 5 { 6 for (int i = 0; i < 10000000; i++) 7 { 8 g_num++; 9 } 10 return ; 11 } 12 13 int main() 14 { 15 //獲取當前毫秒時間戳 16 typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type; 17 microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); 18 long long time1 = tp1.time_since_epoch().count(); 19 20 //建立執行緒 21 thread t1(fun); 22 thread t2(fun); 23 t1.join(); 24 t2.join(); 25 26 cout << "總數:" << g_num << endl; 27 28 //獲取當前毫秒時間戳 29 microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); 30 long long time2 = tp2.time_since_epoch().count(); 31 cout << "耗時:" << time2 - time1 << "ms" << endl; 32 33 getchar(); 34 return 1; 35 }
執行結果:多次測試輸出均為20000000,耗時在1.3s左右
五:總結
c++11的原子類atomic相比使用加鎖機制效能有2~3倍提升,對於共享變數能用原子型別的就不要再用加鎖機制了。
掃碼關注公眾號
專注分享Java,C/C++,STL,Spring框架,mybatis框架,mysql,redis,分散式,高併發,設計模式,爬蟲,docker,shell程式設計等相關技術,在這裡一起探討,一起學習,一起進步,不定期分享視訊書籍資源,充分利用碎片化時間,讓我們的技術之路更加有樂趣。