detach()函数的作用:
主线程不和子线程汇合了;
子线程原本关联的主线程,现在就不在和主线程关联了,这个子线程就会驻留在后台运行;
该子线程会被C++运行时库接管,当子线程执行完毕后,由运行时库(实际上是守护线程,这个要知道linux的一些相关进程线程的知识才懂,如果不懂,就大致理解为有人接管就可以了)清理该线程相关资源
detach()函数的作用的坑点在未验证前自己想:可能发生的问题
从上面的detach的作用,我们就能看到问题点。由于主线程 和 子线程分离了,那么传递参数的时候就要特别注意了。
如果从主线程传递的参数,不是值传递,而是指针,引用;;;
那么在主线程早于子线程完成的时候,子线程用的这个地址还存在吗?
如果不存在了,代码就有问题了
detach函数坑点的总结:
从上一节的代码例子中我们将普通类型值的传递,C++自带类(string)的值传递,自定义类的值传递,普通类型引用的传递,C++自带类(string)的引用传递,自定义类的值引用传递,普通类型值的ref(引用)传递,C++自带类(string)的ref(引用)传递,自定义类的ref(引用)传递,做了测试,发现如下规律:
尽量值传递,不要用引用。虽然在VS2017下,没有问题,但是还是不建议用,因为不知道在其他编辑器上有没有问题。
正常引用也会被 thread 拷贝一份,因此引用传递也不会改变 实参的值。
如果一定要用引用,从前面的例子来看,加上ref(T t)才是真的改变实参值的方法。
那么传递的如果是指针呢?--不行
通过代码在 join()下验证,发现,传递的指针在子线程和主线程的值都一样。
这意味着,在detach()下,从主线程new 出来的int空间,当主线程先执行完毕后,这块空间就被销毁了,如果这时候 子线程还在用,就会有问题。
class Teacher162 {
public:
void funpoint(int *num) {
cout << "子线程 id为 = " << this_thread::get_id() << " funpoint num = " << num << " * num = " << *num << endl;
}
};
void main() {
Teacher162 tea;
int *pint = new int(100);
cout << "主线程 id为 = " << this_thread::get_id() << " pint = " << pint << " *pint = " << *pint << endl;
thread mythread(&Teacher162::funpoint,tea, pint);
mythread.join();
//主线程 id为 = 11684 pint = 000001260FAE7730 *pint = 100
// 子线程 id为 = 3172 funpoint num = 000001260FAE7730 * num = 100
}
如果存在参数存在类型转换,这个类型转换是在主线程完成的?还是子线程完成的?
若传递的参数类对象,避免隐式隐式转换。这个点的理解在于:在参数有隐式转换的时候
class Teacher162 {
public:
void funpoint(int *num) {
cout << "子线程 id为 = " << this_thread::get_id() << " funpoint num = " << num << " * num = " << *num << endl;
}
void funstring(const string str) {
for (int i= 0; i < 10;i++) {
cout << "子线程 id为 = " << this_thread::get_id() << " funstring str = " << str << " & str = " << &str << endl;
}
}
};
void main(){
//不要做隐式转换的,例如需要一个 string,但是我们传递的是 char[],不能直接传递,我们要转换一下
Teacher162 tea;
char sourcestr[] = "nihao";
cout << "主线程 id为 = " << this_thread::get_id() << " sourcestr = " << sourcestr << " &sourcestr = " << &sourcestr << endl;
//需要string,我们传递的是char[],那么一定存在一个从char[]到string的 类型转换了 ,
//问题是:这个类型转换是在什么时候发生的呢?是在主线程还是里子线程?如果在子线程中,那么有没有可能还没有转的时候主线程就执行完毕了,你还转个啥?
//实际中,确实是在子线程中转的。因此在detach下隐式类型转换
//thread mythread(&Teacher162::funstring, tea, sourcestr);//不要有隐式的类型转换
//fix方案,是在传递参数的地方弄一个临时变量,实验证明,临时变量是在的构造是在主线程完成的。
thread mythread(&Teacher162::funstring, tea, new string(sourcestr));
mythread.detach();
}