关闭

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

标签: C++并发实战3向thread传递参数
6149人阅读 评论(5) 收藏 举报
分类:

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

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:441254次
    • 积分:6110
    • 等级:
    • 排名:第4221名
    • 原创:187篇
    • 转载:7篇
    • 译文:1篇
    • 评论:81条
    博客专栏
    最新评论