目錄
1、範例演示線程運行的開始和結束
程序運行起來,生成一個進程,該進程所屬的主線程開始自動運行;main()函數就是主線程,main()函數返回,則整個進程執行完畢。
主線程從main()開始執行,所以自己創建的線程,也需要從一個函數(初始函數)開始運行,一旦這個函數運行完畢,就代表着這個線程運行結束。
整個進程是否執行完畢的標誌是主線程是否執行完,如果主線程執行完畢了,就代表整個進程執行完畢了!
此時,一情況下:如果其他子線程還沒有執行完畢,那麼這些子線程也會被操作系統強行終止。
所以,一船情況下,得到一個結論:如果想保持子線程(自己用代碼創建的線程)的運行狀態的話,那麼要讓主線程一直保持運行,不要讓主線程運行完畢。
[這條規則也有例外,後續會解這種例外,目前先這樣理解和記憶]
編寫多線程程序條件:
a)包含一個頭文件<thread>
b)初始函數。
c)main中創建子線程
大家必須明確一點:有兩個線程在跑,相當於整個程序的執行有兩條線在同時走,所以,可以同時幹兩個事,即使一條線被堵住了,另外一條線是可以通行的,這就是多線程。
1.1 thread:標準庫裏的類
1.2 join()
加入/匯合,說白了就是阻塞,阻塞主線程,讓主線程等待子線程執行完畢,子線程和主線程匯合,然後主線程再往下走!
如果主線程執行完畢了,但子線程沒執行完畢,這種程序不臺格的;
一個書寫良好的程序,應該是主線程等待子線程執行完畢後,自己才能最終退出。
1.3 detach()
傳統多線程程序主線程要等待子線程執行完畢,然後自己再最後退出;
detach:分離,也就是主線程不和子線程匯合了,你主線程執行你的,我子線程執行我的,你主線程也不必等我子線程運行結束,主線程可以先執行結束,這並不影響子線程的執行。
爲什麼引入detach():我們創建了很多子線程,讓主線程逐個等待子線程結束,這種編程方法不太好,所以引入了detach();
一旦detach()之後,與這個主線程關聯的thread對象就會失去與這個主線程的關聯,此時這個子線程就會駐留在後臺運行(主線程與子線程失去聯繫)
這個子線程就相當於被C++運行時庫接管,當這個子線程執行完成後,由運行時庫負責清理該線程相關的資源(守護線程)
detach()使線程去自己的控制。
#include<iostream>
#include<thread>
using namespace std;
void myprint()
{
cout <<"線程開始執行了!" << endl;
cout << "線程執行結束了!" << endl;
}
int main()
{
//myprint可調用對象。
//(1)創建了線程,線程執行起點(入口)myprint();(2)myprint線程開始執行。
thread myobj(myprint);
//阻塞主線程並等待myprint子線程執行完
//主線程阻塞到這裏等待myprint()執行完,當子線程執行完畢,這個join()就執行完畢,主線程就繼續往下執行
myobj.join();
//myobj.detach(); //一旦調用detach(),就不能再使用join(),否則系統會報告錯誤;detach()應用比較少!
cout << "主線程執行!" << endl;
system("pause");
return 0;
}
1.4 joinable()
判斷是否可以使用join()或者detach()的;返回true(可以join或者detach)。
#include<iostream>
#include<thread>
using namespace std;
void myprint()
{
cout << "線程開始執行了!" << endl;
cout << "線程執行結束了!" << endl;
}
int main()
{
thread myobj(myprint);
if (myobj.joinable())
{
cout << "1:myobj.joinable() == true" << endl;
myobj.join();
}
else
{
cout << "1:myobj.joinable() == false" << endl;
}
if (myobj.joinable())
{
cout << "2:myobj.joinable() == true" << endl;
myobj.detach();
}
else
{
cout << "2:myobj.joinable() == false" << endl;
}
cout << "主線程執行!" << endl;
system("pause");
return 0;
}
2.其他創建線程的方法
2.1 用類對象(可調用對象),以及一個問題範例
大家可能還有一個疑問:一旦調用了detach(),那我主線程執行結束了,這裏用的這個ta對象還在嗎?(對象不在了)
解釋:實際上這個對象是被 複製 到線程中去;執行完主線程後,ta會被銷燬,但是所複製的TA對象依舊存在,所以只要這個Ta類對象沒有引用,沒有指針,那麼就不會產生問題。
#include<iostream>
#include<thread>
using namespace std;
//類中包含operator(),此類的對象爲可調用對象
class Ta
{
public:
int &m_i;
Ta(int &i) : m_i(i)
{
cout << "Ta()構造函數被執行了!" << endl;
};
Ta(const Ta &ta):m_i(ta.m_i)
{
cout << "Ta()複製構造函數被執行了!" << endl;
}
~Ta()
{
cout << "~Ta()析構函數被執行了!" << endl;
}
void operator()()
{
cout << "我的線程operator()開始執行了!"<< endl;
cout << "我的線程operator()執行結束了!" << endl;
cout << "m_i的值爲:" << m_i <<endl;
}
};
int main()
{
int myi = 6;
Ta ta(myi);
thread myobj(ta);//ta可調用對象
//myobj.join(); //等待子線程執行結束
//此時,如果主線程執行完了,myi就被釋放了;子線程還沒執行完,就會出現不可預料的bug;
//myobj.detach();
cout << "主線程執行!" << endl;
system("pause");
return 0;
}
2.2 用lambda表達式
#include<iostream>
#include<thread>
using namespace std;
//類中包含operator(),此類的對象爲可調用對象
int main()
{
auto myLamdba = [] {
cout << "我的線程開始執行了"<< endl;
cout << "我的線程執行結束了" << endl;
};
thread myobj(myLamdba);//ta可調用對象
myobj.join(); //等待子線程執行結束
cout << "主線程執行!" << endl;
system("pause");
return 0;
}
注:該文是C++11併發多線程視頻教程筆記,詳情可學習:https://study.163.com/course/courseMain.htm?courseId=1006067356