C++11多線程 線程啓動、結束、創建多線程方法

目錄

1、範例演示線程運行的開始和結束

1.1 thread:標準庫裏的類

1.2 join()

1.3 detach()

1.4 joinable()

2.其他創建線程的方法

2.1 用類對象(可調用對象),以及一個問題範例

2.2 用lambda表達式

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章