天天看點

C++11并發與多線程筆記(2) 線程啟動、結束,建立線程多法、join,detach

第二節 線程啟動、結束,建立線程多法、join,detach

C++11并發與多線程筆記(2) 線程啟動、結束,建立線程多法、join,detach

一、範例示範線程運作的開始

  • 程式運作起來,生成一個程序,該程序所屬的主線程開始自動運作;當主線程從main()函數傳回,則整個程序執行完畢
  • 主線程從main()開始執行,那麼我們自己建立的線程,也需要從一個函數開始運作(初始函數),一旦這個函數運作完畢,線程也結束運作
  • 整個程序是否執行完畢的标志是:主線程是否執行完,如果主線程執行完畢了,就代表整個程序執行完畢了,此時如果其他子線程還沒有執行完,也會被強行終止【此條有例外,以後會解釋】

建立一個線程:

  1. 包含頭檔案thread
  2. 寫初始函數
  3. 在main中建立thread

必須要明白:有兩個線程在跑,相當于整個程式中有兩條線在同時走,即使一條被阻塞,另一條也能運作

#include <iostream>
#include <thread>
using namespace std;

void myPrint()
{
	cout << "我的線程開始運作" << endl;
	//-------------
	//-------------
	cout << "我的線程運作完畢" << endl;
	return;
}

int main()
{
	//(1)建立了線程,線程執行起點(入口)是myPrint;(2)執行線程
	thread myThread(myPrint);

	//(2)阻塞主線程并等待myPrint執行完,當myPrint執行完畢,join()就執行完畢,主線程繼續往下執行
	//join意為彙合,子線程和主線程回合
	myThread.join();

	//設定斷點可看到主線程等待子線程的過程
	//F11逐語句,就是每次執行一行語句,如果碰到函數調用,它就會進入到函數裡面
	//F10逐過程,碰到函數時,不進入函數,把函數調用當成一條語句執行

	//(3)傳統多線程程式中,主線程要等待子線程執行完畢,然後自己才能向下執行
	//detach:分離,主線程不再與子線程彙合,不再等待子線程
	//detach後,子線程和主線程失去關聯,駐留在背景,由C++運作時庫接管
	//myThread.detach();

	//(4)joinable()判斷是否可以成功使用join()或者detach()
	//如果傳回true,證明可以調用join()或者detach()
	//如果傳回false,證明調用過join()或者detach(),join()和detach()都不能再調用了
	if (myThread.joinable())
	{
		cout << "可以調用可以調用join()或者detach()" << endl;
	}
	else
	{
		cout << "不能調用可以調用join()或者detach()" << endl;
	}
	
	cout << "Hello World!" << endl;
	return 0;
}
           

重要補充:

線程類參數是一個可調用對象。

一組可執行的語句稱為可調用對象,c++中的可調用對象可以是函數、函數指針、lambda表達式、bind建立的對象或者重載了函數調用運算符的類對象。

二、其他建立線程的方法

①建立一個類,并編寫圓括号重載函數,初始化一個該類的對象,把該對象作為線程入口位址

class Ta
{
public:
	void operator()() //不能帶參數
	{
		cout << "我的線程開始運作" << endl;
		//-------------
		//-------------
		cout << "我的線程運作完畢" << endl;
	}
};

//main函數裡的:
	Ta ta;
	thread myThread(ta);
	myThread.join();
           

②lambda表達式建立線程

//main函數中
auto lambdaThread = [] {
		cout << "我的線程開始執行了" << endl;
		//-------------
		//-------------
		cout << "我的線程開始執行了" << endl;
	};

	thread myThread(lambdaThread);
	myThread.join();
           

③把某個類中的某個函數作為線程的入口位址

class Data_
{
public:
    void GetMsg(){}
    void SaveMsh(){}
};
//main函數裡
    Data_ s;
    //第一個&意思是取址,第二個&意思是引用,相當于std::ref(s)
    //thread oneobj(&Data_::SaveMsh,s)傳值也是可以的
    //在其他的構造函數中&obj是不會代表引用的,會被當成取位址
    //調用方式:對象成員函數位址,類執行個體,[成員函數參數]
	//第二個參數可以傳遞對象s,也可以傳遞引用std::ref(s)或&s
	//傳遞s,會調用拷貝構造函數在子線程中生成一個新的對象
	//傳遞&,子線程中還是用的原來的對象,是以就不能detach,因為主線程運作完畢會把該對象釋放掉
    thread oneobj(&Data_::SaveMsh,&s);
    thread twoobj(&Data_::GetMsg,&s);
    oneobj.join();
    twoobj.join();
           

繼續閱讀