C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针相关的知识,希望对你有一定的参考价值。

文章目录

C++ thread线程类

线程类thread,提供RAII式线程的创建和销毁。创建线程时传入线程要执行的代码段(函数、lamda表达式)和参数,thread析构函数会自动销毁线程。

C++线程库通过构造一个线程对象来启动一个线程,该线程对象中就包含了线程运行时的上下文环境,比如:线程函数、线程栈、线程起始状态等以及线程ID等,所有操作全部封装在一起,最后在底层统一传递给_beginthreadex() 创建线程函数来实现 (注意:_beginthreadex是windows中创建线程的底层c函数)。

std::thread()创建一个新的线程可以接受任意的可调用对象类型(带参数或者不带参数),包括lambda表达式(带变量捕获或者不带),函数(全局函数或者成员函数),函数对象。

线程启动:thread对象构造函数

通过全局函数构造

#include<iostream>
#include<thread>
#include <windows.h>
using std::cout;
using std::endl;
void threadRoute(int a, int b)

	cout << "I am a new thread of " << std::this_thread::get_id() << endl;
	cout << a + b << endl;
	cout << "sleep start" << endl;
	Sleep(3000);
	cout << "sleep end" << endl;

int main()

	int a = 10, b = 20;
	cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
	std::thread t(threadRoute, a, b);//thread对象构造函数指定线程执行函数
	t.join();//线程等待,防止出现孤儿线程
	system("pause");

VS上运行:

I am the main thread,and my thread id is 22368
I am a new thread of 11944
30
sleep start
sleep end
请按任意键继续. . .

通过lamda表达式构造

#include<iostream>
#include<thread>

using std::cout;
using std::endl;

int main()

	int a = 10, b = 20;
	cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
	std::thread t([=]
		cout << "I am a new thread of " << std::this_thread::get_id() << endl;
		cout << a + b << endl;
	);
	t.join();//线程等待,防止出现孤儿线程
	system("pause");

结果:

I am the main thread,and my thread id is 31056
I am a new thread of 25312
30
请按任意键继续. . .

通过函数对象构造

#include<iostream>
#include<thread>

using std::cout;
using std::endl;

struct funcClass 

	void operator()(int a, int b)
	
		cout << "ID:" << std::this_thread::get_id() << endl;
		cout << a + b << endl;
	
;

int main()

	funcClass fc;//函数对象构造线程时候,必须先有函数对象,操作符不能是静态的
	std::thread t(fc, 10, 20);
	t.join();
	system("pause");
	return 0;


结果:

ID:29648
30

通过成员函数构造

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

	static void memberFunc(int a, int b)
	
		cout << "hello from class member function :" << this_thread::get_id() << endl;
		cout << a + b << endl;
	
;

int main(int argc, char** argv)

	thread t1(A::memberFunc, 10, 20);
	t1.join();
	system("pause");
	return 0;

结果:

hello from class member function :32868
30
请按任意键继续. . .

线程结束

创建一个线程,默认状态是joinable状态,需要主线程等待,如果不希望去等待退出的线程,需要在线程退出之前使用线程对象的成员函数detach来线程分离。

加入式:join()

join():会主动地等待线程的终止。在调用进程中join(),当新的线程终止时,join()会清理相关的资源,然后返回,调用线程再继续向下执行。 由于join()清理了线程的相关资源,thread对象与已销毁的线程就没有关系了,因此一个线程的对象每次你只能使用一次join(),当你调用的join()之joinable()就将返回false了。

#include<iostream>
#include<thread>

using std::cout;
using std::endl;

void threadRoute()

	cout << "ID:" << std::this_thread::get_id() << endl;


int main()

	cout << "Main ID:" << std::this_thread::get_id() << endl;
	std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
	cout << t.joinable() << endl;//默认是joinable状态
	t.join();//线程等待,防止出现孤儿线程
	cout << t.joinable() << endl;//join一次就会把线程资源释放掉,现在已经是false了
	system("pause");

结果:

Main ID:1652
ID:16668
1
0

分离式:detach()

detach:会从调用线程中分理出新的线程,之后不能再与新线程交互。 就像是你和你女朋友分手,那之后你们就不会再有联系(交互)了,而她的之后消费的各种资源也就不需要你去埋单了(清理资源)。此时调用joinable()必然是返回false。分离的线程线程变成了后台进程(孤儿进程),在Linux将由init接管,在c++中由库接管。

#include<iostream>
#include<thread>
#include<windows.h>

using std::cout;
using std::endl;

void threadRoute()

	Sleep(3000);
	cout << "ID:" << std::this_thread::get_id() << endl;



int main()

	cout << "Main ID:" << std::this_thread::get_id() << endl;
	std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
	cout << t.joinable() << endl;//默认是joinable状态
	t.detach();
	cout << t.joinable() << endl;//detach函数会将线程分离,不需要主线程join
	system("pause");


结果:

Main ID:27840
1
0
请按任意键继续. . . ID:20548

注意:必须在thread对象销毁之前做出选择,这是因为线程可能在你加入或分离线程之前,就已经结束了,之后如果再去分离它,线程可能会在thread对象销毁之后继续运行下去。

示例1:线程结束后再join

貌似不会报错,没啥影响

#include<iostream>
#include<thread>
#include<windows.h>

using std::cout;
using std::endl;

void threadRoute()

	cout << "ID:" << std::this_thread::get_id() << endl;


int main()

	cout << "Main ID:" << std::this_thread::get_id() << endl;
	std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
	cout << t.joinable() << endl;//默认是joinable状态	//1

	Sleep(3000);

	cout << t.joinable() << endl;	//1

	t.join();//线程等待,防止出现孤儿线程
	cout << t.joinable() << endl;//join一次就会把线程资源释放掉,现在已经是false了	//0
	system("pause");

结果:

Main ID:1948
1
ID:32100
1
0
请按任意键继续. . .

示例2:线程结束后再detach

貌似也没啥影响。。。。不会报错

#include<iostream>
#include<thread>
#include<windows.h>

using std::cout;
using std::endl;

void threadRoute()

	cout << "ID:" << std::this_thread::get_id() << endl;


int main()

	cout << "Main ID:" << std::this_thread::get_id() << endl;
	std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
	cout << t.joinable() << endl;//默认是joinable状态

	Sleep(3000);

	t.detach();
	cout << t.joinable() << endl;//detach函数会将线程分离,不需要主线程join
	system("pause");


结果:

Main ID:4000
1
ID:8124
0
请按任意键继续. . .

线程安全的thread

thread对象可以转移所有权(?左值,move())

thread object is movable,not copyable,like std::unique_ptr or std::ifstream. std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而我们可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue); 值得一提的是,被转化的左值,其生命期并没有随着左右值的转化而改变。如果期望std::move转化的左值变量lvalue能立即被析构,那么肯定会失望了。

#include<iostream>
#include<thread>

using namespace std;
void some_function();

int main()

	thread t1(some_function); 
	thread t2 = move(t1); //采用std::move移动语义将t1的所有权移动到t2,
	//此时t2接管运行some_function(),而t1此时没有执行线程和其关联
	t1 = thread(some_function); //t1仍然是左值

智能指针管理thread对象(?)

我们知道主线程创建新线程之后,主线程应该还需要去做其它事情而不仅仅是等待其它线程退出。主线程去做其它事情,在join函数之前,主线程可能会因为调用了其它函数而造成异常,这样主线程可能就错过join函数直接去异常处理了。因此,为了保证joinable状态的线程不会成为孤儿进程,可以将thread对象交给智能指针,智能指针析构函数中进行join。

#include<iostream>
#include<thread>

using std::cout;
using std::endl;

void threadRoute()//全局函数

	cout << "ID:" << std::this_thread::get_id() << endl;

class Unique_ptr 
public:
	Unique_ptr(std::thread& t)//这里使用引用传参,传递的就是new出来的那一个线程对象
		:pt(t) 
	~Unique_ptr()
	
		if (pt.joinable())
			pt.join();
	
	Unique_ptr(const Unique_ptr&) = delete;
	Unique_ptr operator=(const Unique_ptr&) = delete;
private:
	std::thread& pt;
;

void func()

	cout << "Main ID:" << std::this_thread::get_id() << endl;
	std::thread t(threadRoute);
	Unique_ptr pth(t);
//pth对象在此调用析构函数,调用线程join函数

int main()

	func();
	system("pause");


结果:

Main ID:18180
ID:29264
请按任意键继续. . .

参考文章:C++11线程对象thread

以上是关于C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针的主要内容,如果未能解决你的问题,请参考以下文章

c++多线程在异常环境下的等待

❥关于C++之多线程┆<thread>join()detach()

40.C++11多线程

40.C++11多线程

40.C++11多线程

c++11 thread学习笔记