C++11多线程 多线程传参详解
Posted u012507022
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11多线程 多线程传参详解相关的知识,希望对你有一定的参考价值。
1.传递临时对象做线程参数
1.1要避免的陷阱1
用detach()时,如果主线程先结束,变量就会被回收;所以用detach()的话,不推荐用引用,同时绝对不能用指针。
1.2要避免的陷阱2
只要临时对象的用临时构造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;
1.3总结
- 若传递int这种简单类型参数,建议都是值传递,不要引用,防止节外生枝
- 如果传递类对象,避免隐式类型转换。全部都在创建线程这一行就构建出临时对象,然后在函数参数里用引用来接;否则系统还会多构造一次对象。
- 终极结论:建议不使用detach(),只使用join();这样就不存在局部变量失效导致线程对内存的非法引用问题。
2.临时对象作为线程参数继续
2.1线程ID概念
Id是个数字,每一个线程(不管是主线程还是子线程)实际上都对应一个数字,而且每一个线程对应的这个数字都不同。也就是说,不同的线程,他的线程id必然不同;
线程ID可以用C++标准库里的函数来获取。std::this_thread::get_id()来获取。
2.2临时对象构造时机抓捕
通过这个例子也可以看出,临时对象后在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;
3.传递类对象、智能指针作为线程参数
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;
4. 用成员函数指针做线程函数
#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
以上是关于C++11多线程 多线程传参详解的主要内容,如果未能解决你的问题,请参考以下文章