C++并发实战3:向thread传递参数

来源:互联网 发布:董小飒淘宝赚多少钱 编辑:程序博客网 时间:2024/05/02 00:46

         在创建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。

原创粉丝点击