结论:
当传递一个类对象作为线程参数时,不论是用字面值接受,还是用引用接受,
thread()都会将这个对象拷贝一份,所以我们在线程函数中修改这个对象,没法对主线程中的对象产生影响.
一.线程id
std::this_thread::get_id():获取线程id
二.经验
thread()+detach():给子线程传递参数时,使用临时对象作为参数,子线程函数的参数在主线程退出前构造出来,最后即使父子线程分离,也不用担心非法访问的问题.
void fun(const test&re)
{
//dosomething
}
int main()
{
//...
int v = 100;
thread t(fun,test(v));
t.detach();
//...
return 0;
}
thread()+join():不用关心上述问题,所以能用join(),一定使用join().
三.std::ref 传递对象,detach()结尾
在第二点描述中,由于子线程将参数的内容进行了拷贝,所以如果我们在子线程函数中修改参数,将不会影响到主线程,但是有的时候我们是希望子线程中去修改某些数据.
实参是一个对象,形参用const引用接受,但是子线程中还是重新的将实参对象拷贝了一份
我们修改这个对象肯定不能引起主线程中这个对象的改动,这样下面这个函数应运而生.
std::ref 函数:明确的告诉编译器传递一个可以对主线程对象产生影响的引用,
而不是"假引用",还进行了拷贝构造,导致没法影响.
//线程函数中修改对象
15 void thread_fun(const A&src)
16 {
17 src.v = 999;
18 }
//......
23 A obj(m);
24
25 thread t1(thread_fun,obj);
正确使用ref()函数:
23 A obj(m);
24
25 thread t1(thread_fun,std::ref(obj));
//将不会调用拷贝构造函数,在线程函数中修改对象,即就是对主线程的对象产生影响
四.传递智能指针作为线程函数参数
使用智能指针,一定搭配join(),否则会产生内存的非法访问
因为以detach()结尾,主线程退出,智能指针释放内存,将会把内存还给OS
如果子线程继续访问,是个大BUG
unique_ptr<int> p(new int(998));
std::thread t1(thread_fun,std::move(p));
五.用成员函数指针作为线程函数
class A{
public:
A(int m ):val(m){ //... }
int m;
void thread_fun(int m){ //... } //该函数将作为线程运行函数
};
int main()
{
A obj(10);
thread obj(&A::thread_work,std::ref(obj),15);
//第一个参数是成员函数
//第三个参数开始才是真正给线程函数的参数
obj.join();
//一定用join(),如果不去修改对象
//可以考虑用detach,因为也会将对象复制一份,不过也就不能用ref
return 0;
}
调用拷贝构造,意味着可以使用detach,因为此时这份内存子线程函数也有一份
如果需要修改原来对象的值,那么就可以使用ref()函数,真正的去引用这个对象,但是此时不能使用detach.