C++11併發程式設計:原子操作atomic

蝸牛201發表於2018-12-14

一:概述

  專案中經常用遇到多執行緒操作共享資料問題,常用的處理方式是對共享資料進行加鎖,如果多執行緒操作共享變數也同樣採用這種方式。

  為什麼要對共享變數加鎖或使用原子操作?如兩個執行緒操作同一變數過程中,一個執行緒執行過程中可能被核心臨時掛起,這就是執行緒切換,當核心再次切換到該執行緒時,之前的資料可能已被修改,不能保證原子操作。

  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程式設計等相關技術,在這裡一起探討,一起學習,一起進步,不定期分享視訊書籍資源,充分利用碎片化時間,讓我們的技術之路更加有樂趣。

相關文章