在创建thread object时可以向线程传递参数,默认情况下,参数会被拷贝到线程空间以供线程执行时存取,即使参数是引用也是这样。
情形1:
void f(int i,std::string const& s);
boost::thread t(f,3,”hello”); //字符串常量“hello”会被转换为string,该string在线程中存在。
情形2:
void f(int i,std::string const& s);
void oops(int some_param)
{
char buffer[1024];
sprintf(buffer, "%i",some_param);
boost::thread t(f,3,buffer); //换成boost::thread t(f,3,string(buffer))保证安全
t.detach();
}
这里会存在一个潜在的风险:当oops退出时,buffer会被销毁,但是如果此时在子线程中buffer还没有被转化成string,将会出现dangle pointer。一个解决办法是:boost::thread t(f,3,string(buffer));此时thread在构造时就会将buffer转换为string,并将string拷贝至子线程地址空间。
情形3:thread构造会拷贝其参数
#include<iostream>
#include<string>
#include<boost/thread.hpp>
#include<unistd.h>
using namespace std;
class test{
public:
test(int i=0):data(i){}
test(const test& one){
data=one.data;
cout<<"test::copy constructor"<<endl;
}
test& operator=(const test& one){
data=one.data;
cout<<"test::operator=()"<<endl;
return *this;
}
~test(){
cout<<"test::destructor"<<endl;
}
public:
int data;
};
void func(test& one){
cout<<"func get the data "<<one.data<<endl;
}
void oops(){
test one(10);
boost::thread t(func,one);
t.join();
}
int main(){
oops();
return 0;
}
程序输出:
test::copy constructor
test::copy constructor
test::copy constructor
test::copy constructor
test::copy constructor
test::destructor
test::copy constructor
test::destructor
test::destructor
test::copy constructor
test::copy constructor
test::destructor
test::destructor
test::destructor
test::destructor
func get the data 10 //这里是线程函数的输出
test::destructor
test::destructor
说明:即使线程函数func采用引用方式,thread并不知道这一情形,所以在thread object在构造时会盲目的拷贝test one,然后thread将这个对象拷贝到线程地址空间作为internal copy,此后线程函数引用的是线程地址空间的那个internal copy,线程执行完毕,thread会销毁internal copy。对于这一点和boost::bind也一样,boost::bind也会拷贝参数。至于上面程序出现的那么多拷贝和析构输出已经我已无力解释了sorry。
情形4: 有些时候需要向线程传递一个引用,由线程执行一些计算最后这个计算结果将在主线程中使用,可以用boost::ref传递一个引用到线程空间。
#include<iostream>
#include<string>
#include<boost/thread.hpp>
#include<boost/ref.hpp>
#include<unistd.h>
using namespace std;
class test{
public:
test(int i=0):data(i){}
test(const test& one){
data=one.data;
cout<<"test::copy constructor"<<endl;
}
test& operator=(const test& one){
data=one.data;
cout<<"test::operator=()"<<endl;
return *this;
}
~test(){
cout<<"test::destructor"<<endl;
}
public:
int data;
};
void func(test& one){
cout<<"func get the data "<<one.data++<<endl;
}
void oops(){
test one(10);
boost::thread t(func,boost::ref(one));
t.join();
cout<<"oops() get the data "<<one.data<<endl;
}
int main(){
oops();
return 0;
}
程序输出:
func get the data 10 //子线程修改数据
oops() get the data 11 //主线程将得到子线程修改后的结果,因为boost::ref是传递引用,没有拷贝构造之类的
test::destructor
情形5:thread传递函数对象
#include<iostream>
#include<boost/thread.hpp>
using namespace std;
class test{
public:
test(int i=0):data(i){}
~test(){
cout<<"test::destructor"<<endl;
}
test(const test& one){
data=one.data;
}
test& operator=(const test& one){
data=one.data;
return *this;
}
void operator()(){
cout<<"test::operator() "<<data<<endl;
}
void show(){
cout<<"test::show() "<<data<<endl;
}
public:
int data;
};
void oops(){
boost::thread t((test()));
t.join();
}
int main(){
oops();
return 0;
}
程序输出:
test::destructor //函数对象没有产生copy constructor
test::destructor
test::destructor
test::operator() 0
test::destructor
情形6:仿照boost::bind将对象的成员函数作为线程函数
#include<iostream>
#include<boost/thread.hpp>
using namespace std;
class test{
public:
test(int i=0):data(i){}
~test(){
cout<<"test::destructor"<<endl;
}
test(const test& one){
data=one.data;
}
test& operator=(const test& one){
data=one.data;
return *this;
}
void operator()(){
cout<<"test::operator() "<<data<<endl;
}
void show(){
cout<<"test::show() "<<data<<endl;
}
public:
int data;
};
void oops(){
test one(10);
boost::thread my_thread(&test::show,&one);
my_thread.join();
}
int main(){
oops();
return 0;
}
程序输出:
test::show() 10
test::destructor
说明:此时thread的线程将调用one::show(),thread将&one当做对象地址传递到线程中。
情形7:向thread传递指针:普通指针和智能指针。
#include<iostream>
#include<boost/thread.hpp>
#include<boost/shared_ptr.hpp>
using namespace std;
class test{
public:
test(int i=0):data(i){}
~test(){
cout<<"test::destructor"<<endl;
}
test(const test& one){
data=one.data;
}
test& operator=(const test& one){
data=one.data;
return *this;
}
public:
int data;
};
void fun(boost::shared_ptr<test> ptr){
ptr->data++;
}
void fun_(test* ptr){
ptr->data++;
}
void oops(){
boost::shared_ptr<test> ptr(new test(10));
boost::thread my_thread(fun,ptr);
my_thread.join();
cout<<"shared_ptr "<<ptr->data<<endl;
test* one=new test(10);
boost::thread t(fun_,one);
t.join();
cout<<"test* "<<one->data<<endl;
delete one;
}
int main(){
oops();
return 0;
}
程序输出:
shared_ptr 11 //智能指针
test* 11 //普通指针
test::destructor
test::destructor
说明:传递指针给线程函数,thread拷贝的是指针对象,故线程对指针所指对象的修改将会影响到主线程中的对象。注意的是智能指针可能会引起对象生命周期的延长,若thread::detach那么智能指针肯定比普通裸指针安全,特别是detach后oops退出,智能指针管理的对象由于引用计数不会被析构,而普通裸指针由于oops退出析构了局部对象导致dangle pointer。
情形8:std::unique_ptr的movable语义传递参数
void process_big_object(std::unique_ptr<big_object>);
std::unique_ptr<big_object> p(new big_object);
p->prepare_data(42);
std::thread t(process_big_object,std::move(p));//为什么一定要用std::move?std::unique_ptr是个左值对象,std::move的功能是将左值转为右值使用
说明:std::unique_ptr不能共享所有权,但是可以转移所有权,采用std::move()语义后原来的std::unique_ptr将为NULL。