线程类thread,提供RAII式线程的创建和销毁。创建线程时传入线程要执行的代码段(函数、lamda表达式)和参数,thread析构函数会自动销毁线程。
C++线程库通过构造一个线程对象来启动一个线程,该线程对象中就包含了线程运行时的上下文环境,比如:线程函数、线程栈、线程起始状态等以及线程ID等,所有操作全部封装在一起,最后在底层统一传递给_beginthreadex() 创建线程函数来实现 (注意:_beginthreadex是windows中创建线程的底层c函数)。
std::thread()创建一个新的线程可以接受任意的可调用对象类型(带参数或者不带参数),包括lambda表达式(带变量捕获或者不带),函数(全局函数或者成员函数),函数对象。
#include
#include
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");
}
#include
#include
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
#include
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
#include
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()清理了线程的相关资源,thread对象与已销毁的线程就没有关系了,因此一个线程的对象每次你只能使用一次join(),当你调用的join()之joinable()就将返回false了。
#include
#include
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:会从调用线程中分理出新的线程,之后不能再与新线程交互。 就像是你和你女朋友分手,那之后你们就不会再有联系(交互)了,而她的之后消费的各种资源也就不需要你去埋单了(清理资源)。此时调用joinable()必然是返回false。分离的线程线程变成了后台进程(孤儿进程),在Linux将由init接管,在c++中由库接管。
#include
#include
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 object is movable,not copyable,like std::unique_ptr or std::ifstream. std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而我们可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast
#include
#include
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仍然是左值
}
我们知道主线程创建新线程之后,主线程应该还需要去做其它事情而不仅仅是等待其它线程退出。主线程去做其它事情,在join函数之前,主线程可能会因为调用了其它函数而造成异常,这样主线程可能就错过join函数直接去异常处理了。因此,为了保证joinable状态的线程不会成为孤儿进程,可以将thread对象交给智能指针,智能指针析构函数中进行join。
#include
#include
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");
}