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

原创 2013年12月03日 15:01:49

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

[C++11 并发编程] 03 - 向线程传递参数

我们可以通过std::thread的构造函数向线程传递参数,但是默认情况下,这些参数的拷贝会被传递到线程内部,即使参数申明为引用,也是如此: void f(int i,std::string cons...
  • yamingwu
  • yamingwu
  • 2015年08月07日 18:10
  • 3275

boost::thread使用引用参数

boost::thread到bind始终是使用copy方式,不管是值类型还是引用类型的指针,都是用copy方式传递,导致结果无法取得。 例如: void ReceiveMessage(int msg...
  • zh_geo
  • zh_geo
  • 2015年11月18日 09:34
  • 998

Boost::Thread使用示例

(1)最简单方法#include #include boost::mutex io_mutex; void hello() { std::cout
  • zhuxiaoyang2000
  • zhuxiaoyang2000
  • 2011年07月06日 14:48
  • 42696

C++11并发之std::thread

std::thread 在 #include 头文件中声明,因此使用 std::thread 时需要包含 #include 头文件。...
  • liuker888
  • liuker888
  • 2015年07月12日 11:08
  • 11294

c++11特性之std::thread--进阶二

继续C++11的std::thread之旅!下面讨论如何给线程传递参数 这个例子是传递一个string#include #include #include void thread_functio...
  • wangshubo1989
  • wangshubo1989
  • 2015年11月04日 00:00
  • 4800

pthread与std::thread对比用法

Thread std::thread的构造函数方便得出人意料,这得感谢std::bind这个神奇的函数。在std::thread的构造函数里,你可以直接传递一个函数和这个函数的参数列表给这个线程。你...
  • matrixyy
  • matrixyy
  • 2016年03月19日 07:05
  • 5816

一、C++11多线程std::thread的简单使用(上)

出处:http://blog.csdn.net/star530/article/details/24186783 昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:”看到前面那俩教练没...
  • aa375809600
  • aa375809600
  • 2015年12月10日 01:08
  • 3310

std::thread 学习初步

标准库(C++0x)中的 thread 用起来似乎蛮简单的。例子一个 std::thread 对象可以接收普通的函数函数对象类的成员函数lambda 函数作为参数。#include #include...
  • dbzhang800
  • dbzhang800
  • 2011年07月06日 23:58
  • 17798

c++11的多线程支持二(线程参数)

std::thread支持为线程传入参数,且支持任意类型、任意数目的参数。参数传入方式如下所示: #include #include #include #include void fun(...
  • hustyiyi
  • hustyiyi
  • 2014年01月13日 14:38
  • 3748

C++并发实战2:thread::join和thread::detach

thread::join()是个简单暴力的方法,主线程等待子进程期间什么都不能做,一般情形是主线程创建thread object后做自己的工作而不是简单停留在join上。thread::join()还...
  • liuxuejiang158
  • liuxuejiang158
  • 2013年12月02日 14:11
  • 17990
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++并发实战3:向thread传递参数
举报原因:
原因补充:

(最多只允许输入30个字)