亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

探究在C++程序并發時保護共享數據的問題

2020-05-23 14:18:16
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了探究在C++程序并發時保護共享數據的問題,也有利于大家更好地理解C++多線程的一些機制,需要的朋友可以參考下

我們先通過一個簡單的代碼來了解該問題。

同步問題

我們使用一個簡單的結構體 Counter,該結構體包含一個值以及一個方法用來改變這個值:

 

 
  1. struct Counter { 
  2. int value; 
  3.  
  4. void increment(){ 
  5. ++value; 
  6. }; 

然后啟動多個線程來修改結構體的值:

 

 
  1. int main(){ 
  2. Counter counter; 
  3.  
  4. std::vector<std::thread> threads; 
  5. for(int i = 0; i < 5; ++i){ 
  6. threads.push_back(std::thread([&counter](){ 
  7. for(int i = 0; i < 100; ++i){ 
  8. counter.increment(); 
  9. })); 
  10.  
  11. for(auto& thread : threads){ 
  12. thread.join(); 
  13.  
  14. std::cout << counter.value << std::endl; 
  15.  
  16. return 0; 

我們啟動了5個線程來增加計數器的值,每個線程增加了100次,然后在線程結束時打印計數器的值。

但我們運行這個程序的時候,我們是希望它會答應500,但事實不是如此,沒人能確切知道程序將打印什么結果,下面是在我機器上運行后打印的數據,而且每次都不同:

 

 
  1. 442 
  2. 500 
  3. 477 
  4. 400 
  5. 422 
  6. 487 

問題的原因在于改變計數器值并不是一個原子操作,需要經過下面三個操作才能完成一次計數器的增加:

首先讀取 value 的值

然后將 value 值加1

將新的值賦值給 value

但你使用單線程來運行這個程序的時候當然沒有任何問題,因此程序是順序執行的,但在多線程環境中就有麻煩了,想象下下面這個執行順序:

Thread 1 : 讀取 value, 得到 0, 加 1, 因此 value = 1

Thread 2 : 讀取 value, 得到 0, 加 1, 因此 value = 1

Thread 1 : 將 1 賦值給 value,然后返回 1

Thread 2 : 將 1 賦值給 value,然后返回 1

這種情況我們稱之為多線程的交錯執行,也就是說多線程可能在同一個時間點執行相同的語句,盡管只有兩個線程,交錯的現象也很明顯。如果你有更多的線程、更多的操作需要執行,那么這個交錯是必然發生的。

有很多方法來解決線程交錯的問題:

信號量 Semaphores

原子引用 Atomic references

Monitors

Condition codes

Compare and swap

在這篇文章中我們將學習如何使用信號量來解決這個問題。信號量也有很多人稱之為互斥量(Mutex),同一個時間只允許一個線程獲取一個互斥對象的鎖,通過 Mutex 的簡單屬性就可以用來解決交錯的問題。

使用 Mutex 讓計數器程序是線程安全的

在 C++11 線程庫中,互斥量包含在 mutex 頭文件中,對應的類是 std::mutex,有兩個重要的方法 mutex:lock() 和 unlock() ,從名字上可得知是用來鎖對象以及釋放鎖對象。一旦某個互斥量被鎖,那么再次調用 lock() 返回堵塞值得該對象被釋放。

為了讓我們剛才的計數器結構體是線程安全的,我們添加一個 set:mutext 成員,并在每個方法中通過 lock()/unlock() 方法來進行保護:

 

 
  1. struct Counter { 
  2. std::mutex mutex; 
  3. int value; 
  4.  
  5. Counter() : value(0) {} 
  6.  
  7. void increment(){ 
  8. mutex.lock(); 
  9. ++value; 
  10. mutex.unlock(); 
  11. }; 

然后我們再次測試這個程序,打印的結果就是 500 了,而且每次都一樣。

異常和鎖

現在讓我們來看另外一種情況,想象我們的的計數器有一個減操作,并在值為0的時候拋出異常:

 

 
  1. struct Counter { 
  2. int value; 
  3.  
  4. Counter() : value(0) {} 
  5.  
  6. void increment(){ 
  7. ++value; 
  8.  
  9. void decrement(){ 
  10. if(value == 0){ 
  11. throw "Value cannot be less than 0"
  12.  
  13. --value; 
  14. }; 

然后我們不需要修改類來訪問這個結構體,我們創建一個封裝器:

 

 
  1. struct ConcurrentCounter { 
  2. std::mutex mutex; 
  3. Counter counter; 
  4.  
  5. void increment(){ 
  6. mutex.lock(); 
  7. counter.increment(); 
  8. mutex.unlock(); 
  9.  
  10. void decrement(){ 
  11. mutex.lock(); 
  12. counter.decrement();  
  13. mutex.unlock(); 
  14. }; 

大部分時候該封裝器運行挺好,但是使用 decrement 方法的時候就會有異常發生。這是一個大問題,一旦異常發生后,unlock 方法就沒被調用,導致互斥量一直被占用,然后整個程序就一直處于堵塞狀態(死鎖),為了解決這個問題我們需要用 try/catch 結構來處理異常情況:

 

 
  1. void decrement(){ 
  2. mutex.lock(); 
  3. try { 
  4. counter.decrement(); 
  5. catch (std::string e){ 
  6. mutex.unlock(); 
  7. throw e; 
  8. mutex.unlock(); 

這個代碼并不難,但看起來很丑,如果你一個函數有 10 個退出點,你就必須為每個退出點調用一次 unlock 方法,或許你可能在某個地方忘掉了 unlock ,那么各種悲劇即將發生,悲劇發生將直接導致程序死鎖。

接下來我們看如何解決這個問題。

自動鎖管理

當你需要包含整段的代碼(在我們這里是一個方法,也可能是一個循環體或者其他的控制結構),有這么一種好的解決方法可以避免忘記釋放鎖,那就是 std::lock_guard.

這個類是一個簡單的智能鎖管理器,但創建 std::lock_guard 時,會自動調用互斥量對象的 lock() 方法,當 lock_guard 析構時會自動釋放鎖,請看下面代碼:

 

 
  1. struct ConcurrentSafeCounter { 
  2. std::mutex mutex; 
  3. Counter counter; 
  4.  
  5. void increment(){ 
  6. std::lock_guard<std::mutex> guard(mutex); 
  7. counter.increment(); 
  8.  
  9. void decrement(){ 
  10. std::lock_guard<std::mutex> guar(mutex); 
  11. mutex.unlock(); 
  12. }; 

是不是看起來爽多了?

使用 lock_guard ,你不再需要考慮什么時候要釋放鎖,這個工作已經由 std::lock_guard 實例幫你完成。

結論

在這篇文章中我們學習了如何通過信號量/互斥量來保護共享數據。需要記住的是,使用鎖會降低程序性能。在一些高并發的應用環境中有其他更好的解決辦法,不過這不在本文的討論范疇之內。

你可以在 Github 上獲取本文的源碼.

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美裸体视频网站| 亚洲国产精品电影在线观看| 久久国产精品亚洲| 欧美福利视频网站| 尤物99国产成人精品视频| 亚洲第一综合天堂另类专| 久久国产精品影片| 欧美激情xxxx性bbbb| 国产精品视频最多的网站| 精品久久久久国产| 97涩涩爰在线观看亚洲| 久久久久久国产三级电影| 国产精品久久久久久久久久99| 在线观看视频99| 国产精品综合网站| 国产欧美精品日韩| 国内精品模特av私拍在线观看| 国产精品一区电影| 亚洲国产成人久久综合一区| 欧美精品在线网站| 国产日韩欧美中文| 精品亚洲永久免费精品| 91国语精品自产拍在线观看性色| 国产精品久久久久77777| 日本高清视频精品| 国产精品电影一区| 国产精品网红直播| 国产欧美一区二区三区视频| 亚洲欧美制服另类日韩| 亚洲欧美激情视频| 国产精品大片wwwwww| 国产精品狠色婷| 亚洲jizzjizz日本少妇| 亚洲国产精品久久91精品| 国产成人在线视频| 日韩av不卡电影| 日韩av综合网站| 亚洲va久久久噜噜噜久久天堂| 久久久久999| 亚洲黄色av女优在线观看| 久久福利视频导航| 夜夜嗨av色综合久久久综合网| 精品无人国产偷自产在线| 欧美日韩国产中文精品字幕自在自线| 欧洲成人在线观看| 国产亚洲欧美日韩精品| 91av在线影院| 欧美日韩精品在线视频| 中文字幕av一区二区| 欧洲午夜精品久久久| 成人激情在线观看| 欧美精品xxx| 自拍偷拍免费精品| 日韩av中文字幕在线| 欧美在线视频网站| 日韩男女性生活视频| 91av在线国产| 欧美中文字幕视频在线观看| 欧美高清在线观看| 91亚洲va在线va天堂va国| 欧美疯狂性受xxxxx另类| 国产精品一区二区女厕厕| 久久精品亚洲一区| 55夜色66夜色国产精品视频| 欧美激情videoshd| 日韩av在线免费观看一区| 国产精品成人一区二区三区吃奶| 亚洲aⅴ男人的天堂在线观看| 成人乱人伦精品视频在线观看| 深夜精品寂寞黄网站在线观看| 91高清免费视频| 日韩网站免费观看高清| 欧美日韩福利电影| 国产精品女人网站| 欧美亚洲激情在线| 欧美激情欧美激情在线五月| 国产精品久久久久高潮| 国产剧情日韩欧美| 色yeye香蕉凹凸一区二区av| 欧美精品做受xxx性少妇| 欧美一级成年大片在线观看| 国产亚洲欧美日韩一区二区| 亚洲性生活视频| 久久国产精品久久久久久久久久| 日韩av电影在线网| 色偷偷偷亚洲综合网另类| 国产精品久久久久久久久久ktv| 久久久久久欧美| 亚洲国产欧美一区二区三区同亚洲| 国产视频欧美视频| 国产欧美一区二区白浆黑人| 91欧美精品成人综合在线观看| 精品久久久久久久大神国产| 国产欧美va欧美va香蕉在线| 91探花福利精品国产自产在线| 欧美国产亚洲精品久久久8v| 成人高清视频观看www| 亚洲成人网在线观看| 久久久电影免费观看完整版| 亚洲欧美精品一区二区| 色婷婷久久一区二区| 亚洲人成欧美中文字幕| 国产成人精品一区二区在线| 欧美在线激情视频| 日韩免费在线免费观看| 最近的2019中文字幕免费一页| 亚洲在线第一页| 欧美电影在线观看网站| www.久久撸.com| 欧美日本黄视频| 国产91在线高潮白浆在线观看| 久久久亚洲成人| 欧美精品一区在线播放| 亚洲精品视频免费在线观看| 91国自产精品中文字幕亚洲| 国产视频999| 精品亚洲永久免费精品| 久久精品视频在线播放| 久久久久亚洲精品| 91国产美女在线观看| 国产精品永久免费视频| 九九热视频这里只有精品| 日韩av一卡二卡| 亚洲欧美国产高清va在线播| 日韩综合视频在线观看| 一区二区三区日韩在线| 亚洲欧美在线播放| 成人福利网站在线观看11| 国产精品av免费在线观看| 欧美亚洲另类激情另类| 在线观看精品国产视频| 91欧美精品午夜性色福利在线| 国产精品日韩在线一区| 超碰97人人做人人爱少妇| 国产成人精品日本亚洲专区61| 国产精品久久二区| 色小说视频一区| 亚洲精品videossex少妇| 亚洲片av在线| 国产一区二区三区在线播放免费观看| 国产精品视频成人| 亚洲欧美一区二区三区情侣bbw| 91爱爱小视频k| 欧美日韩国产一区在线| 欧美电影在线观看完整版| 欧美日韩亚洲一区二| 亚洲嫩模很污视频| 成人国产精品久久久久久亚洲| 精品国产一区二区三区久久久狼| 97色在线观看| 国内外成人免费激情在线视频| 最新国产精品亚洲| 97婷婷大伊香蕉精品视频| 欧美激情乱人伦| 欧美在线视频一区二区| 国产精品日韩在线| 国产极品jizzhd欧美| 在线播放精品一区二区三区| 亚洲电影免费观看高清完整版| 亚洲xxxx妇黄裸体| 国产精品ⅴa在线观看h| 美女av一区二区| 久久久精品中文字幕| 欧美日韩成人黄色|