1. 说明
在子线程函数中进行参数传递,实际上是Thread类的构造函数对传递的参数进行了拷贝,拷贝到线程独立的内存中,及时参数是引用的形式,也可以在新线程中进行访问,如果参数传递时的类型不一致,在线程的上下文中会对类型进行隐式类型转换。不过当传递的参数是指针类型时需要特别注意,可能会有问题,具体见下文。
2. 普通参数传递
如果在子线程中不需要对传递过来的参数进行更改操作,那么传递参数时正常传递就行,为避免误操作,可以使用const关键字进行修饰 :
#include <iostream>
using namespace std;
#include <thread>
void myprint(const string s)
{
cout << s << endl;
}
int main()
{
string s = "xiaoming";
thread mythread(myprint, s);
mythread.join();
std::cout << "主线程:"<<s<<endl;
return 0;
}
3. 传递引用(使用ref)
如果想在子线程中修改主线程中传递过来的数据,需要使用**std::ref()**函数:
#include <iostream>
using namespace std;
#include <thread>
void myprint(string& s)
{
s = "xiaohong......";
cout <<"子线程:" << s << endl;
}
int main()
{
string s = "xiaoming";
thread mythread(myprint, ref(s));
mythread.join();
std::cout << "主线程:"<<s<<endl;
return 0;
}
4. 传递指针变量
Thread类虽然会对参数类型进行转换,但是遇到指针变量,还是需要进行显式类型转换,否则会出现问题。
悬垂指针:当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针
#include <iostream>
using namespace std;
#include <thread>
void myprint(const string& mbuffer)
{
cout <<"子线程:" << mbuffer << endl;
}
int main()
{
char buffer[] = "this is a test....";
thread mythread(myprint,string(buffer));//使用string进行显式类型转换,避免悬垂指针
mythread.join();
std::cout << "主线程:运行结束...."<<endl;
return 0;
}
4. 传递自定义的类
在自定义类中使用关键字mutable定义了一个变量,可以方便更改操作。实际将自定义类对象传输到子线程中,Thread构造函数会调用自定义类的拷贝构造函数,实际传输到子线程的类并非主线程中的原始类对象:
#include <iostream>
using namespace std;
#include <thread>
class A
{
public:
A(int a) :m_i(a)
{
cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
~A()
{
cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
public:
mutable int m_i;
};
void myprint(const A& a)//这里虽然使用了引用&,但输出结果发现并非是真正的引用,实际上引用的是拷贝构造函数复制出来的另一份对象a
{
a.m_i = 2;//对变量进行更改
cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
}
int main()
{
int mvar = 1;
A a(mvar);
thread mythread(myprint,a);
mythread.join();
cout << "主线程(类中的变量):" << a.m_i << endl;//输出原始类对象中的m_i变量
std::cout << "主线程:运行结束...."<<endl;
return 0;
}
运行结果如下:发现两次输出的m_i的变量值是不一样的,而且类A的拷贝构造函数执行了
若想做到对自定义类真正的引用,需要使用std::ref()函数
修改上述代码如下:
thread mythread(myprint,std::ref(a));//传递参数时使用 ref 函数才能做到整正的引用
此时再输出结果会发现:并未调用自定义类中的拷贝构造函数
5. 传递自定义的类成员函数
注意使用引用的方式进行参数传递
#include <iostream>
using namespace std;
#include <thread>
class A
{
public:
A(int a) :m_i(a)
{
cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
~A()
{
cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
}
//添加成员函数
void thread_work(int num)
{
cout << "[成员函数thread_work执行了....]" << endl;
}
public:
mutable int m_i;
};
void myprint(const A& a)
{
a.m_i = 2;//对变量进行更改
cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
}
int main()
{
int mvar = 1;
A myobj(mvar);
//第一个参数是成员函数名,第二个参数是类对象名(注意使用引用的方式),第三个参数是成员函数需要的参数
thread mythread(&A::thread_work,&myobj,15);
mythread.join();
std::cout << "主线程:运行结束...."<<endl;
return 0;
}
6. 传递智能指针(使用std::move()函数)
#include <iostream>
using namespace std;
#include <thread>
void myprint(unique_ptr<int> pzn)
{
}
int main()
{
unique_ptr<int> mypzn(new int(100));
thread mythread(myprint,std::move(mypzn));
mythread.join();
std::cout << "主线程:运行结束...."<<endl;
return 0;
}