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

首頁(yè) > 編程 > C++ > 正文

C++多線程編程時(shí)的數(shù)據(jù)保護(hù)

2020-05-23 14:18:38
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

這篇文章主要介紹了C++多線程編程時(shí)的數(shù)據(jù)保護(hù),作者針對(duì)C++11版本中的新特性做出了一些解說(shuō),需要的朋友可以參考下

在編寫(xiě)多線程程序時(shí),多個(gè)線程同時(shí)訪問(wèn)某個(gè)共享資源,會(huì)導(dǎo)致同步的問(wèn)題,這篇文章中我們將介紹 C++11 多線程編程中的數(shù)據(jù)保護(hù)。

數(shù)據(jù)丟失

讓我們從一個(gè)簡(jiǎn)單的例子開(kāi)始,請(qǐng)看如下代碼:

 

 
  1. #include <iostream> 
  2. #include <string> 
  3. #include <thread> 
  4. #include <vector> 
  5.  
  6. using std::thread; 
  7. using std::vector; 
  8. using std::cout; 
  9. using std::endl; 
  10.  
  11. class Incrementer 
  12. private
  13. int counter; 
  14.  
  15. public
  16. Incrementer() : counter{0} { }; 
  17.  
  18. void operator()() 
  19. for(int i = 0; i < 100000; i++) 
  20. this->counter++; 
  21.  
  22. int getCounter() const 
  23. return this->counter; 
  24. }  
  25. }; 
  26.  
  27. int main() 
  28. // Create the threads which will each do some counting 
  29. vector<thread> threads; 
  30.  
  31. Incrementer counter; 
  32.  
  33. threads.push_back(thread(std::ref(counter))); 
  34. threads.push_back(thread(std::ref(counter))); 
  35. threads.push_back(thread(std::ref(counter))); 
  36.  
  37. for(auto &t : threads) 
  38. t.join(); 
  39.  
  40. cout << counter.getCounter() << endl; 
  41.  
  42. return 0; 

這個(gè)程序的目的就是數(shù)數(shù),數(shù)到30萬(wàn),某些傻叉程序員想要優(yōu)化數(shù)數(shù)的過(guò)程,因此創(chuàng)建了三個(gè)線程,使用一個(gè)共享變量 counter,每個(gè)線程負(fù)責(zé)給這個(gè)變量增加10萬(wàn)計(jì)數(shù)。

這段代碼創(chuàng)建了一個(gè)名為 Incrementer 的類,該類包含一個(gè)私有變量 counter,其構(gòu)造器非常簡(jiǎn)單,只是將 counter 設(shè)置為 0.

緊接著是一個(gè)操作符重載,這意味著這個(gè)類的每個(gè)實(shí)例都是被當(dāng)作一個(gè)簡(jiǎn)單函數(shù)來(lái)調(diào)用的。一般我們調(diào)用類的某個(gè)方法時(shí)會(huì)這樣 object.fooMethod(),但現(xiàn)在你實(shí)際上是直接調(diào)用了對(duì)象,如object(). 因?yàn)槲覀兪窃诓僮鞣剌d函數(shù)中將整個(gè)對(duì)象傳遞給了線程類。最后是一個(gè) getCounter 方法,返回 counter 變量的值。

再下來(lái)是程序的入口函數(shù) main(),我們創(chuàng)建了三個(gè)線程,不過(guò)只創(chuàng)建了一個(gè) Incrementer 類的實(shí)例,然后將這個(gè)實(shí)例傳遞給三個(gè)線程,注意這里使用了 std::ref ,這相當(dāng)于是傳遞了實(shí)例的引用對(duì)象,而不是對(duì)象的拷貝。

現(xiàn)在讓我們來(lái)看看程序執(zhí)行的結(jié)果,如果這位傻叉程序員還夠聰明的話,他會(huì)使用 GCC 4.7 或者更新版本,或者是 Clang 3.1 來(lái)進(jìn)行編譯,編譯方法:

 

 
  1. g++ -std=c++11 -lpthread -o threading_example main.cpp 

運(yùn)行結(jié)果:

 

 
  1. [lucas@lucas-desktop src]$ ./threading_example 
  2. 218141 
  3. [lucas@lucas-desktop src]$ ./threading_example 
  4. 208079 
  5. [lucas@lucas-desktop src]$ ./threading_example 
  6. 100000 
  7. [lucas@lucas-desktop src]$ ./threading_example 
  8. 202426 
  9. [lucas@lucas-desktop src]$ ./threading_example 
  10. 172209 

但等等,不對(duì)啊,程序并沒(méi)有數(shù)數(shù)到30萬(wàn),有一次居然只數(shù)到10萬(wàn),為什么會(huì)這樣呢?好吧,加1操作對(duì)應(yīng)實(shí)際的處理器指令其實(shí)包括:

 

 
  1. movl counter(%rip), %eax 
  2. addl $1, %eax 
  3. movl %eax, counter(%rip) 

首個(gè)指令將裝載 counter 的值到 %eax 寄存器,緊接著寄存器的值增1,然后將寄存器的值移給內(nèi)存中 counter 所在的地址。

我聽(tīng)到你在嘀咕:這不錯(cuò),可為什么會(huì)導(dǎo)致數(shù)數(shù)錯(cuò)誤的問(wèn)題呢?嗯,還記得我們以前說(shuō)過(guò)線程會(huì)共享處理器,因?yàn)橹挥袉魏?。因此在某些點(diǎn)上,一個(gè)線程會(huì)依照指令執(zhí)行完成,但在很多情況下,操作系統(tǒng)會(huì)對(duì)線程說(shuō):時(shí)間結(jié)束了,到后面排隊(duì)再來(lái),然后另外一個(gè)線程開(kāi)始執(zhí)行,當(dāng)下一個(gè)線程開(kāi)始執(zhí)行時(shí),它會(huì)從被暫停的那個(gè)位置開(kāi)始執(zhí)行。所以你猜會(huì)發(fā)生什么事,當(dāng)前線程正準(zhǔn)備執(zhí)行寄存器加1操作時(shí),系統(tǒng)把處理器交給另外一個(gè)線程?

我真的不知道會(huì)發(fā)生什么事,可能我們?cè)跍?zhǔn)備加1時(shí),另外一個(gè)線程進(jìn)來(lái)了,重新將 counter 值加載到寄存器等多種情況的產(chǎn)生。誰(shuí)也不知道到底發(fā)生了什么。

正確的做法

解決方案就是要求同一個(gè)時(shí)間內(nèi)只允許一個(gè)線程訪問(wèn)共享變量。這個(gè)可通過(guò) std::mutex 類來(lái)解決。當(dāng)線程進(jìn)入時(shí),加鎖、執(zhí)行操作,然后釋放鎖。其他線程想要訪問(wèn)這個(gè)共享資源必須等待鎖釋放。

互斥(mutex) 是操作系統(tǒng)確保鎖和解鎖操作是不可分割的。這意味著線程在對(duì)互斥量進(jìn)行鎖和解鎖的操作是不會(huì)被中斷的。當(dāng)線程對(duì)互斥量進(jìn)行鎖或者解鎖時(shí),該操作會(huì)在操作系統(tǒng)切換線程前完成。

而最好的事情是,當(dāng)你試圖對(duì)互斥量進(jìn)行加鎖操作時(shí),其他的線程已經(jīng)鎖住了該互斥量,那你就必須等待直到其釋放。操作系統(tǒng)會(huì)跟蹤哪個(gè)線程正在等待哪個(gè)互斥量,被堵塞的線程會(huì)進(jìn)入 "blocked onm" 狀態(tài),意味著操作系統(tǒng)不會(huì)給這個(gè)堵塞的線程任何處理器時(shí)間,直到互斥量解鎖,因此也不會(huì)浪費(fèi) CPU 的循環(huán)。如果有多個(gè)線程處于等待狀態(tài),哪個(gè)線程最先獲得資源取決于操作系統(tǒng)本身,一般像 Windows 和 Linux 系統(tǒng)使用的是 FIFO 策略,在實(shí)時(shí)操作系統(tǒng)中則是基于優(yōu)先級(jí)的。

現(xiàn)在讓我們對(duì)上面的代碼進(jìn)行改進(jìn):

 

 
  1. #include <iostream> 
  2. #include <string> 
  3. #include <thread> 
  4. #include <vector> 
  5. #include <mutex> 
  6.  
  7. using std::thread; 
  8. using std::vector; 
  9. using std::cout; 
  10. using std::endl; 
  11. using std::mutex; 
  12.  
  13. class Incrementer 
  14. private
  15. int counter; 
  16. mutex m; 
  17.  
  18. public
  19. Incrementer() : counter{0} { }; 
  20.  
  21. void operator()() 
  22. for(int i = 0; i < 100000; i++) 
  23. this->m.lock(); 
  24. this->counter++; 
  25. this->m.unlock(); 
  26.  
  27. int getCounter() const 
  28. return this->counter; 
  29. }  
  30. }; 
  31.  
  32. int main() 
  33. // Create the threads which will each do some counting 
  34. vector<thread> threads; 
  35.  
  36. Incrementer counter; 
  37.  
  38. threads.push_back(thread(std::ref(counter))); 
  39. threads.push_back(thread(std::ref(counter))); 
  40. threads.push_back(thread(std::ref(counter))); 
  41.  
  42. for(auto &t : threads) 
  43. t.join(); 
  44.  
  45. cout << counter.getCounter() << endl; 
  46.  
  47. return 0; 

注意代碼上的變化:我們引入了 mutex 頭文件,增加了一個(gè) m 的成員,類型是 mutex,在operator()() 中我們鎖住互斥量 m 然后對(duì) counter 進(jìn)行加1操作,然后釋放互斥量。

再次執(zhí)行上述程序,結(jié)果如下:

 

 
  1. [lucas@lucas-desktop src]$ ./threading_example 
  2. 300000 
  3. [lucas@lucas-desktop src]$ ./threading_example 
  4. 300000 

這下數(shù)對(duì)了。不過(guò)在計(jì)算機(jī)科學(xué)中,沒(méi)有免費(fèi)的午餐,使用互斥量會(huì)降低程序的性能,但這總比一個(gè)錯(cuò)誤的程序要強(qiáng)吧。

防范異常

當(dāng)對(duì)變量進(jìn)行加1操作時(shí),是可能會(huì)發(fā)生異常的,當(dāng)然在我們這個(gè)例子中發(fā)生異常的機(jī)會(huì)微乎其微,但是在一些復(fù)雜系統(tǒng)中是極有可能的。上面的代碼并不是異常安全的,當(dāng)異常發(fā)生時(shí),程序已經(jīng)結(jié)束了,可是互斥量還是處于鎖的狀態(tài)。

為了確保互斥量在異常發(fā)生的情況下也能被解鎖,我們需要使用如下代碼:

 

 
  1. for(int i = 0; i < 100000; i++) 
  2. this->m.lock(); 
  3. try 
  4. this->counter++; 
  5. this->m.unlock(); 
  6. catch(...) 
  7. this->m.unlock(); 
  8. throw

但是,這代碼太多了,而只是為了對(duì)互斥量進(jìn)行加鎖和解鎖。沒(méi)關(guān)系,我知道你很懶,因此推薦個(gè)更簡(jiǎn)單的單行代碼解決方法,就是使用 std::lock_guard 類。這個(gè)類在創(chuàng)建時(shí)就鎖定了 mutex 對(duì)象,然后在結(jié)束時(shí)釋放。

繼續(xù)修改代碼:

 

 
  1. void operator()() 
  2. for(int i = 0; i < 100000; i++) 
  3. lock_guard<mutex> lock(this->m); 
  4.  
  5. // The lock has been created now, and immediatly locks the mutex 
  6. this->counter++; 
  7.  
  8. // This is the end of the for-loop scope, and the lock will be 
  9. // destroyed, and in the destructor of the lock, it will 
  10. // unlock the mutex 

上面代碼已然是異常安全了,因?yàn)楫?dāng)異常發(fā)生時(shí),將會(huì)調(diào)用 lock 對(duì)象的析構(gòu)函數(shù),然后自動(dòng)進(jìn)行互斥量的解鎖。

記住,請(qǐng)使用放下代碼模板來(lái)編寫(xiě):

 

 
  1. void long_function() 
  2. // some long code 
  3.  
  4. // Just a pair of curly braces 
  5. // Temp scope, create lock 
  6. lock_guard<mutex> lock(this->m); 
  7.  
  8. // do some stuff 
  9.  
  10. // Close the scope, so the guard will unlock the mutex 

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
天堂网在线观看国产精品| 欧美娇小性xxxx| 中文字幕在线一区| 国产成人精品一区二区三区四区| 亚洲激情一区二区| 午夜国产一区二区| 涩涩视频在线播放| 小向美奈子av| 亚洲高清av在线| 国产视频一区二区三| 中文字幕在线免费观看视频| 日韩欧美视频免费在线观看| 91美女精品网站| 一女二男3p波多野结衣| 殴美一级特黄aaaaaa| 你懂的网站在线观看网址| 国产农村妇女精品一区二区| 激情五月宗合网| 美女国内精品自产拍在线播放| 日韩av毛片在线观看| 国产美女免费无遮挡| 91久久线看在观草草青青| 久久久久久久久综合| 日韩av一区二区在线观看| 青青草原国产视频| 人人爽人人爽av| 在线播放日韩精品| 日本免费看黄色| 欧美在线免费看| 精品乱码一区二区三四区视频| 国产伦精品一区二区三毛| 免费成人在线影院| 天堂在线免费观看| 欧美激情精品久久久久久大尺度| 成年在线观看免费人视频| 最新日韩一区| 在线这里只有精品| 欧美影院久久久| 99久re热视频这里只有精品6| 亚洲一区二区三区在线免费观看| 僵尸世界大战2 在线播放| 一区二区三区影院| 九色蝌蚪自拍| 中文字幕少妇一区二区三区| 国产一区视频在线看| gogogo影视剧免费观看在线观看| 好吊成人免视频| 男人的天堂一区二区| 亚洲欧美色一区| 精品毛片久久久久久| 亚洲精品97久久中文字幕无码| 欧美国产精品一区二区三区| 美女羞羞视频在线观看| 嫩草成人www欧美| 亚洲精品久久久久国产| 啪啪亚洲精品| 欧美日韩亚洲不卡| 亚洲色图 欧美| 一本色道婷婷久久欧美| 日韩欧美中文字幕公布| 最新久久zyz资源站| 国产视频手机在线| 成人精品视频99在线观看免费| 动漫成人在线观看| 午夜激情视频网| 波多野结衣av无码| 欧美在线观看日本一区| 岛国中文字幕| 韩国19禁主播vip福利视频| 全部a∨一极品视觉盛宴| 一本一道综合狠狠老| 羞羞在线观看网站| 日本a级黄色| 国产精品一区毛片| 青梅竹马是消防员在线| 欧美日韩精品一区二区在线播放| 亚洲一区二区四区蜜桃| 色呦呦在线视频| 国产chinesehd精品露脸| 91美女在线免费观看| 性一交一乱一乱一视频| 日韩欧美一区二区久久婷婷| 激情亚洲综合在线| 国产精品毛片一区二区在线看| 电影av一区| 日本学生初尝黑人巨免费视频| 女性隐私黄www网站视频| 久久爱www久久做| 欧美成人精品欧美一级乱| 欧美精品欧美精品系列| 国产丝袜精品视频| 手机看片福利永久国产日韩| 男人资源网站| 伊人久久亚洲热| 亚洲三区在线观看| 99精品欧美一区二区三区综合在线| 福利片一区二区三区| 一本色道久久综合狠狠躁篇的优点| 日本在线观看天堂男亚洲| 玖玖视频精品| 欧美色欧美亚洲另类二区| jizzjizz中国精品麻豆| 欧美激情视频在线播放| 好吊色一区二区| 国产精品美女免费看| 日韩一区二区三区在线播放| 国产一区亚洲二区| 日本美女高潮视频| 欧美性生交xxxxx久久久| 国产美女av一区二区三区| 黑人巨大猛交丰满少妇| 久久在线观看免费| 特黄视频在线观看| 黄瓜视频网站| 蜜桃免费在线视频| 大片免费播放在线视频| 一级性生活大片| 国内成人精品一区| 青青草一区二区三区| 成人福利视频网| 日本加勒比高清在线| 欧美一区二区三区不卡视频| 国产区av在线| 妺妺窝人体色www聚色窝仙踪| 最近中文字幕mv免费高清电影| 国产一区二区三区四区在线| 色综合天天性综合| 男人添女荫道口喷水视频| 精品无码黑人又粗又大又长| 久久日本片精品aaaaa国产| 国产精品白丝一区二区三区| 亚洲欧美视频在线| 怡红院av久久久久久久| 探花国产精品一区二区| 成人私拍视频| 人妻 丝袜美腿 中文字幕| 影音先锋5566中文源资源| 久久蜜桃香蕉精品一区二区三区| 国产精品九九九九九| 国产日本欧美一区二区三区| 日韩精品一卡二卡三卡四卡无卡| 香蕉成人啪国产精品视频综合网| 在线电影看在线一区二区三区| www.在线欧美| 成人做爰66片免费看网站| 国产原创av在线| 国产成人av电影在线观看| 日韩一级理论片| 午夜国产精品视频| 污视频网站在线| 国内精品久久久久久久久| 国产精品久久久久久久乖乖| 香蕉视频黄色在线观看| 成人动漫av在线| 91色婷婷久久久久合中文| av无码久久久久久不卡网站| 午夜精品免费视频| 男人添女荫道口女人有什么感觉| 草民午夜欧美限制a级福利片| 欧美丰满少妇人妻精品| 欧美一级大黄| 国产欧美亚洲视频| 亚洲欧美在线免费观看| 日本精品性网站在线观看| 亚洲免费成人在线| 亚洲人成电影网站色xx| 伦伦影院午夜日韩欧美限制| 国产日韩视频在线| 激情中文字幕| 999久久久91| 91av影院| 老牛精品亚洲成av人片| 国产日产精品一区二区三区四区的观看方式| aa视频在线观看| 亚洲欧洲一区二区在线播放| 国产区高清在线| 色噜噜一区二区三区| 91亚洲精品在线观看| 国精一区二区| 久久精品123| 亚洲精品中文字幕99999| 激情婷婷丁香| 永久免费毛片在线播放| 日本天堂免费a| 国产精品密蕾丝视频下载| 日本中文字幕一区| 国产传媒在线播放| 亚洲精品国产精品国自产网站| 禁果av一区二区三区| 黄色三级电影网| 精品国产亚洲一区二区三区大结局| 最新欧美电影| 久久亚洲成人av| 成人性做爰aaa片免费看不忠| www日韩tube| 亚洲av成人无码久久精品老人| 亚洲成av人片在线观看无码| 视频福利一区| 人体私拍套图hdxxxx| 国产一区二区三区av在线| 欧美色图片区| 亚洲欧美一区二区三区久久| 欧美 国产 日本| 久久蜜桃av一区精品变态类天堂| 伊人成人开心激情综合网| 青青青草网站免费视频在线观看| 成人免费视频网址| 欧美成a人片免费观看久久五月天| 成人在线视频成人| 捆绑紧缚一区二区三区视频| 亚洲嫩草精品久久| 成人疯狂猛交xxx| 啦啦啦啦免费高清视频在线观看1| 久久久久久av| 国产精品久久久久av免费| 国产极品美女高潮无套嗷嗷叫酒店| 无套内谢大学处破女www小说| 黄色片网站免费在线观看| 久久综合狠狠综合久久激情| 欧美日韩在线网站| 久久精品这里有| 国产黑丝一区二区| a中文字幕www| 992tv成人国产福利在线| 超碰porn在线| 免费在线观看av网址| 久久精品99国产精品酒店日本| 精品国产欧美一区二区三区成人| 中国av一区| 中国china体内裑精亚洲片| 这里只有精品国产| 俄罗斯男人又粗又大| 26uuu国产电影一区二区| 三级黄色片免费观看| 国产嫩bbwbbw高潮| 亚洲一区二区三区四区五区六区| 国产专区精品视频| 青丝免费观看高清影视| 国产黄色大片网站| 国产厕所精品在线观看| 国产精品久久久久久亚洲av| av资源在线免费观看| 国产欧美一区二区精品忘忧草| 最近2019年好看中文字幕视频| 欧美激情一级欧美精品| 国产在线观看精品一区二区三区| 色综合久久综合网欧美综合网| 永久555www成人免费| 欧美成人免费va影院高清| 天堂在线免费观看| 国产盗摄——sm在线视频| 国产66精品久久久久999小说| 伊人久久大香线蕉精品| 伊人网在线综合| 亚洲欧美综合久久久| 国产美女网站在线观看| 欧美激情一区二区三级高清视频| 久久久.com| 波多野结衣视频在线看| 青青草国产成人av片免费| 日韩欧美国产一二三区| 9797在线看片亚洲精品| 日韩av午夜在线观看| 亚洲欧洲成人精品av97| 18free性欧美另类hd| av免费在线播放| 人妖精品videosex性欧美| 中文字幕 久热精品 视频在线| 成人欧美精品一区二区| 超碰成人福利网| 精品无码人妻一区二区免费蜜桃| 免费在线性爱视频| 九色国产在线观看| 国精品产品一区| 国产免费黄视频在线观看| 久久精品99久久久香蕉| 久热中文字幕在线精品首页| 在线免费看a| 无码aⅴ精品一区二区三区| 青青青青久久精品国产一百度| 一区二区三区91| 高清av不卡| 亚洲人成无码www久久久| 首页国产精品| 久久久久无码精品国产sm果冻| 九一国产在线观看| www.欧美精品一二区| 亚洲免费观看在线视频| 国产精品裸体一区二区三区| www.夜色| 精品少妇爆乳无码av无码专区| 国产精品久久久久久久久久久久久久久久久| 开心丁香婷婷深爱五月| 国产偷亚洲偷欧美偷精品| 午夜欧美在线一二页| ,亚洲人成毛片在线播放| 欧美美女直播网站| av女片在线| 成人永久在线| 另类图片亚洲色图| 91尤物国产福利在线观看| 国产乱一区二区| 日韩欧美一级精品久久| 亚洲精品女人久久久| 国产一区免费看| 日本黄色小视频在线观看| 精品国产黄色片| 精品久久久在线观看| 中文在线a√在线8| 很黄很a的视频| 91激情在线观看| 久久久久久久久久久成人| 久草电影在线| 国产一级黄色录像片| 动漫av免费观看| 久久99性xxx老妇胖精品| mm视频在线视频| 亚洲一区二区三区视频在线播放| 亚洲精品乱码电影在线观看| 欧美日韩第一视频| 午夜国产精品理论片久久影院| 黄色大全在线观看| 日韩中文字幕观看| 久久久久亚洲AV成人| 99久久亚洲精品日本无码| 极品尤物av久久免费看| 夜夜爽av福利精品导航| 欧美日韩精品在线一区|