文章12 | 阅读 6489 | 点赞0
用detach()时,如果主线程先结束,变量就会被回收;所以用detach()的话,不推荐用引用,同时绝对不能用指针。
只要临时对象的用临时构造A类对象作为参数传递给线程,那么就一定能够在主线程结束之前,把线程函数的第二个参数构建出来,从而确保即便detach()子线程也安全运行,程序如下:
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//类型转换构造函数,可以把一个int转换成一个类A对象。
A(int a):m_i(a){cout << "A::A(int a)构造函数执行!"<< endl;}
A(const A &a) :m_i(a.m_i){cout << "A::A(A &a)复制构造函数执行!" << endl;}
~A(){cout << "A::~A()析构函数执行!" << endl;}
};
void myprint1(const int &i, char *pmybuf)
{
//通过查看内存可知变量mvar与它的引用mvary地址是相同的,但是传递到myprint()中,
//&i的地址不是mvar的地址,所以这是个假引用,此时引用传递与传值是一样的。
//分析可得,并不是mvar的引用,实际是值传递,那么我们认为,即便是主线程detach了子线程,
//那么子线程用i值任然是安全的!
cout << i << endl;
//第二个参数*pmybuf 是指针,*pmybuf的地址与mybuf[]相同;
//指针在detach子线程时,绝对会有问题;
cout << pmybuf << endl;
}
//此时用 string& 通过一个隐形转换来接收mybuf[]的值,但此时安全吗?
//但是mybuf是 在什么时候转换成string?
//事实上存在mybuf都被回收了,系统才将mybuf去转string的可能性
//所以此方法也是不安全的
void myprint2(const int i, const string &pmybuf)
{
cout << i << endl;
cout << pmybuf << endl;
}
int main()
{
int mvar = 1;
int &mvary = mvar;
char mybuf[] = "This is a test!";
//thread myobj(myprint1, mvar, mybuf);
//string(mybuf)生成临时string对象;我们这里直接将mybuf转换成string对象,
//这是一个可以保证在线程中用肯定有效的对象。
//下个程序进行验证
thread myobj(myprint2, mvar, string(mybuf));
myobj.detach();
cout << "主线程执行!" << endl;
system("pause");
return 0;
}
通过自定义类的方式验证 临时对象可以保证主线程结束之前,把线程函数的参数构建出来
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//类型转换构造函数,可以把一个int转换成一个类A对象。
A(int a) :m_i(a) { cout << "A::A(int a)构造函数执行!" << endl; }
A(const A &a) :m_i(a.m_i) { cout << "A::A(A &a)复制构造函数执行!" << endl; }
~A() { cout << "A::~A()析构函数执行!" << endl; }
};
void myprint(const int i, const A &pmybuf)
{
cout << &pmybuf << endl;// 打印的是pmybuf对象的地址
}
int main()
{
int mvar = 1;
int mysecondpar = 12;
//我们希望mysecondpar转成A类型对象传递给myprint的第二个参数
/*主线程什么都不操作,快速结束主线程,运行程序后可以发现,
没有输出“A::A(int a)构造函数执行!”说明主线程执行完毕,*/
thread myobj(myprint, mvar, mysecondpar);
/*在创建线程的同时构造临时对象的方法传递参数是可行的!
//可以保证在主线程结束之前,构造出来!*/
thread myobj(myprint, mvar, A(mysecondpar));
myobj.detach();
//cout << "主线程执行!" << endl;
return 0;
}
Id是个数字,每一个线程(不管是主线程还是子线程)实际上都对应一个数字,而且每一个线程对应的这个数字都不同。也就是说,不同的线程,他的线程id必然不同;
线程ID可以用C++标准库里的函数来获取。std::this_thread::get_id()来获取。
通过这个例子也可以看出,临时对象后在main()函数中已经构造完毕了。
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//类型转换构造函数,可以把一个int转换成一个类A对象。
A(int a) :m_i(a)
{
cout << "A::A(int a)构造函数执行!"<<this<<"threadid:" <<std::this_thread::get_id()<< endl;
}
A(const A &a) :m_i(a.m_i)
{
cout << "A::A(A &a)复制构造函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
~A()
{
cout << "A::~A()析构函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
};
void myprint2(const A &pmybuf)
{
cout << "子对象myprint的参数地址是" <<&pmybuf<<"threadid"<<std::this_thread::get_id()<<endl;// 打印的是pmybuf对象的地址
}
int main()
{
cout << "主线程id:" << std::this_thread::get_id() <<endl;
int mvar = 2;
//thread myobj(myprint2, mvar); //致命问题是在子线程中构造A类对象
thread myobj(myprint2, A(mvar)); //用了临时对象后,所有的A类对象都在main()函数中已经构造完毕了
myobj.join();
//myobj.detach(); //子线程与主线程分别执行
return 0;
}
std::ref()函数的作用 可以实现真正的引用
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
mutable int m_i;
//类型转换构造函数,可以把一个int转换成一个类A对象。
A(int a) :m_i(a)
{
cout << "A::A(int a)构造函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
A(const A &a) :m_i(a.m_i)
{
cout << "A::A(A &a)复制构造函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
~A()
{
cout << "A::~A()析构函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
};
void myprint2(const A &pmybuf)
{
pmybuf.m_i = 199; //我们修改该值不会影响main()函数
cout << "子对象myprint的参数地址是" << &pmybuf << "threadid" << std::this_thread::get_id() << endl;// 打印的是pmybuf对象的地址
}
int main()
{
A myobj(10); //生成一个类对象
thread mytobj(myprint2, std::ref(myobj));
mytobj.join();
return 0;
}
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void myprint2(unique_ptr<int> pzn)
{
;
}
int main()
{
unique_ptr<int> myp(new int(100));
thread mytobj(myprint2,std::move(myp));
mytobj.join();
return 0;
}
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
mutable int m_i;
//类型转换构造函数,可以把一个int转换成一个类A对象。
A(int a) :m_i(a)
{
cout << "A::A(int a)构造函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
A(const A &a) :m_i(a.m_i)
{
cout << "A::A(A &a)复制构造函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
~A()
{
cout << "A::~A()析构函数执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
void thread_work(int num)
{
cout << "子线程thread——work执行!" << this << "threadid:" << std::this_thread::get_id() << endl;
}
};
int main()
{
A myobj(10);
thread mytobj(&A::thread_work, &myobj, 15);
mytobj.join();
return 0;
}
注:该文是C++11并发多线程视频教程笔记,详情学习:https://study.163.com/course/courseMain.htm?courseId=1006067356
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/u012507022/article/details/85845799
内容来源于网络,如有侵权,请联系作者删除!