C++11线程对象thread

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

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

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

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

通过全局函数构造

#include<iostream>
#include<thread>
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;
}
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");
}

通过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");
}

通过函数对象构造

#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;
}

通过成员函数构造

#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;
}

线程结束

创建一个线程,默认状态是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");
}

分离式:detach()

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

#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.detach();
	cout << t.joinable() << endl;//detach函数会将线程分离,不需要主线程join
	system("pause");
}

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

线程安全的thread

thread对象可以转移所有权

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");
}

猜你喜欢

转载自blog.csdn.net/Vickers_xiaowei/article/details/89880893
今日推荐