//
#include
#include
#include
#include
#include
using namespace std;
//自己建立的線程也要從一個函數(初始函數開始運作):
void myprint()
{
cout << "我的線程開始執行了" << endl;
cout << "我的線程開始執行了1" << endl;
cout << "我的線程開始執行了2" << endl;
cout << "我的線程開始執行了3" << endl;
cout << "我的線程開始執行了4" << endl;
cout << "我的線程開始執行了5" << endl;
cout << "我的線程開始執行了6" << endl;
cout << "我的線程開始執行了7" << endl;
//...
cout << "我的線程執行完畢了" << endl;
}
class TA{
public:
void operator()() //不能帶參數
{
cout << "我的線程operator()開始執行了" << endl;
cout << "我的線程operator()結束執行了" << endl;
}
};
class TA1{
public:
int &m_i;
TA1(int &i) : m_i(i){
cout << "TA()構造函數被執行" << endl;
}
TA1(const TA1 &ta) : m_i(ta.m_i){
cout << "TA()拷貝構造函數被執行" << endl;
}
~TA1(){
cout << "TA()析構函數被執行" << endl;
}
void operator()() //不能帶參數
{
cout << "m_i1的值為:" << m_i << endl;
cout << "m_i1的值為:" << m_i << endl;
cout << "m_i1的值為:" << m_i << endl;
cout << "m_i1的值為:" << m_i << endl;
}
};
int main()
{
//一:範例示範線程運作的開始和結束
//程式運作起來,生成一個程序,該程序所屬的主線程開始自動運作;
cout << "I Love China!" << endl; //實際上這個是主線程在執行,主線程從main()函數傳回,則整個程序執行完畢。
//主線程從main()開始執行,那麼我們自己建立的線程,也需要從一個函數開始運作(初始函數),一旦這個函數運作完畢,就代表着我們這個線程運作結束。
//整個程序是否執行完畢的标志是 主線程是否執行完,如果主線程執行完畢了,就代表整個程序執行完畢了;
//此時,一般情況下:如果其他子線程還沒有執行完畢,那麼這些子線程也會被作業系統強行終止。
//是以,一般情況下,我們得到一個結論:如果大家想保持子線程(自己用代碼建立的線程)的運作狀态的話,那麼大家要讓主線程一直保持運作,不要讓線程運作完畢。
//【這條規律有例外,後續會解釋這種例外,大家目前先這樣了解和記憶】
//a) 包含一個頭檔案thread要包含進來。
//b) 初始函數要寫。
//c) main中開始寫代碼。
//大家必須明确一點:有兩個線程在跑,相當于整個程式的執行有兩條線在同時走,是以,可以同時幹兩個事,
//即使一條線被堵住了,另外一條線還是可以通行的,這就是多線程;
//(1.1) thread: 是個标準庫裡的類
//(1.2) join(): 加入/彙合,說白了就是阻塞,阻塞主線程,讓主線程等待子線程執行完畢,然後子線程和主線程彙合。然後主線程再往下走
//如果主線程執行完畢了,但子線程沒執行完畢,這種程式員是不合格的,寫出來的程式也是不穩定的。
//一個書寫良好的程式,應該是主線程 等待子線程執行完畢後 自己才能最終退出;
//(1.3) detach():傳統多線程程式主線程要等待子線程執行完畢,然後自己再最後退出;
//detach :分離,也就是主線程不和子線程彙合了,你主線程執行你的,我子線程執行我的,你主線程也不必等
//我子線程運作結束, 你可以先執行結束。
//為什麼引入detach(): 我們建立了很多子線程,讓主線程逐個等待子線程結束,這種程式設計方法不太好,是以引入
//了detach();一旦detach()之後, 與這個主線程關聯的thread對象就會失去與這個主線程關聯,此時這個子線程
//就會駐留在背景運作(主線程跟該子線程失去聯系),這個子線程就相當于被C++運作時刻接管,當這個子線程
//指向完成後,由運作時庫負責清理該線程相關的資源(守護線程)。
//detach()使線程myprint失去我們自己的控制。
//(1.4) joinable() : 判斷是否可以成功使用join()或者detach()的;傳回true(可以join或者detach)或者false(不能join不能detach);
//myprint可調用對象
//thread mytobj(myprint); //建立了線程,線程執行起點(入口)myprint(), (2) myprint線程開始執行。
//
//if (mytobj.joinable()){
//cout << "1: joinable() == true" << endl;
//}
//else{
//cout << "1: joinable() == false" << endl;
//}
//阻塞主線程并等待myprint子線程執行完
//mytobj.join(); //主線程阻塞到這裡等待myprint()執行完,當子線程執行完畢,這個join()就執行完畢,主線程就繼續往下走。
//mytobj.detach(); //一旦調用了 detach(), 就不能再用join() 否則系統會報告異常。
//二:其他建立線程的手法
//(2.1)用類對象(可調用對象),以及一個問題範例
//大家可能還有一個疑問:一旦調用了detach(),那我主線程執行結束了,我這裡用的這個ta這個對象還在嗎?(對象不在了)
//這個對象實際上是被複制到線程中去;執行完主線程後,ta會被銷毀,但是所複制TA對象依舊存在。
//是以,隻要你這個TA類對象裡沒有引用,沒有指針,那麼就不會産生問題;
TA ta;
thread mytobj3(ta); // ta :可調用對象
mytobj3.join(); //等待子線程執行結束
int myi = 6;
TA1 ta1(myi);
thread mytobj4(ta1); // ta :可調用對象
mytobj4.join(); //等待子線程執行結束
mytobj4.detach();
//(2.2)用lambda表達式
auto mylamthread = [] {
cout << "我的線程3開始執行了" << endl;
cout << "我的線程3執行結束了" << endl;
};
thread mytobj5(mylamthread);
mytobj5.join();
mytobj5.detach();
cout << "I Love China 1!" << endl;
cout << "I Love China 2!" << endl;
cout << "I Love China 3!" << endl;
cout << "I Love China 4!" << endl;
cout << "I Love China 5!" << endl;
cout << "主線程收尾,最終主線程安全正常退出!" << endl;
system("pause");
}