C++11 ,封裝了thread的多線程的類,這樣對多線程的使用更加方便。ios
多線程的原理我不加贅述,能夠參看操做系統等參考書。多線程
多線程代碼能夠最大化利用計算機性能資源,提升代碼的運行效率,是經常使用優化方法。函數
我不是C++大神,初學階段的菜鳥而已,不少問題我仍是不理解當中的原理,寫這篇博客的緣由,也是記錄本身的學習心得和思路,供本身往後本身思考。性能
首先從簡單的問題入手,如何寫一個多線程的C++代碼?學習
#include<iostream> #include<thread> void fun(int a){ a++; } int main(){ int a=0; std::thread t(fun,a); //建立一個線程t,t調用函數fun,a做爲fun的參數,也要寫到thread的構造函數當中;
t.join(); //啓動線程t,而且阻塞主線程,等到線程t運行結束後,再繼續運行主線程; std::cout<<a<<std::endl; }
上面這段代碼是最簡單的多線程代碼,調用thread類,並利用了thread的構造函數建立一個線程t,thread類的構造函數重載了不少,後面會繼續說到。測試
在這裏要說一下,thread類當中的兩個成員函數,join()和detach()。這兩個成員的做用就像上面代碼的註釋那樣,啓動新生成的線程的,可是區別在於join()函數是啓動子線程而阻塞主線程,當子線程運行結束後,纔會繼續運行主線程。相比之下,detach()函數的做用是啓動子線程,而且讓子線程和主線程分離,子線程和主線程各運行各的,雖然兩個線程會由於共享內存池的緣由在操做系統的層面發生發生阻塞等關係,可是在代碼層次上,兩個線程並不存在誰阻塞誰,極可能主線程已經運行結束了,子線程還在運行。優化
接下來,咱們要說一下類當中的成員函數如何初始化thread類的構造函數。this
對於類的成員函數,咱們須要給出類對象的地址:spa
#include<iostream> #include<thread> class A{ public: void fun(int a,int b){ std::cout<<"this is A thread!"<<a<<std::endl; } }; int main(){ int k=0; A a; std::thread t(&A::fun,a,k,k+1); t.join(); }
std::thread t(&A::fun,a,k,k+1); 這個地方就能夠看出thread類的構造對於成員函數的重載了,std::thread t(函數(成員函數)地址,對象地址,成員函數的參數1,參數2,參數3...)。
相比非成員函數,成員函數須要給出類實例化對象的地址,若是該線程是在同一類的某一成員函數當中被構造,則直接用this關鍵字代替便可。
其實,我在寫成員函數的多線程代碼的時候,發現成員函數的須要傳遞的參數太多會使thread類的構造函數重載失敗,我測試了一下,成員函數最多隻能傳遞4個參數,也就說std::thread類的構造函數最多隻能重載6個參數。
這一點,我並無找到相關文檔獲得證明,只是在寫代碼的時候發現成員函數傳遞參數太多,會一直編譯不經過,偶然間發現這個點的,具體到底對不對,我也不是很肯定。
其次,咱們要說一下加鎖和解鎖的問題。
由於咱們創造的每個線程只要在一個進程內,都是共享內存池的,這樣在讀寫數據可能會發生混亂。
C++11提供了mutex類進行加鎖和解鎖。
#include<iostream> #include<thread> #include<mutex> std::mutex mut; class A{ public: volatile int temp; A(){ temp=0; } void fun(int num){ int count=10; while(count>0){ mut.lock(); temp++; std::cout<<"thread_"<<num<<"...temp="<<temp<<std::endl; mut.unlock(); count--; } } void thread_run(){ std::thread t1(&A::fun,this,1); std::thread t2(&A::fun,this,2); t1.join(); t2.join(); } }; int main(){ A a; a.thread_run(); }
而後,咱們說一下volatile關鍵字。
volatile和const關鍵很類似,都是修飾變量的,只是兩者功能不同。
volatile在多線程當中常常使用,由於在某一線程屢次調用某一個變量,編譯器會進行優化,將該變量存放在在寄存器當中,不會每次都從內存當中讀入。果真該變量同時在其餘線程當中被修改,這樣就會發生髒讀取錯誤。
而加上volatile修飾,則會提醒編譯器,這個變量可能會被改變,不能存放到寄存器當中,須要每次都從內存當中讀取。
最後,咱們說一下join()和detach()的使用技巧。