C++11多线程学习---线程函数的参数传递

线程参数传递要记住一个重要的事情,传递的参数是存在新线程一个内部的转存站中,之后在函数执行的时候再传递给函数本身的。

这种机制会引发两个问题:

1.临时参数的未及时构造

void f(int i,std::string const& s);

void oops(int some_param)
{
    char buffer[1024];
    sprintf(buffer,"%i",some_param);
    std::thread t(f,3,buffer); //这里的buffer指向的是一个栈上的指针,所以在线程真正要执行这个函数f的时候,这个栈可能已经释放了,因此会存在异常
    t.detach();
}
虽然函数f的第二个参数接受的是一个std::string,但是我们传递进去的是一个char*,而这个char*在创建这个线程的时候并不会直接就转换为std::string.这里出现的问题就是调用时机与传递参数的时机不一致所导致的,所以一种更安全的写法是先把这个string构造好:

void f(int i,std::string const& s);

void oops(int some_param)
{
    char buffer[1024];
    sprintf(buffer,"%i",some_param);
    std::thread t(f,3,std::string(buffer)); //这里首先将buffer构造成string传进去
    t.detach();
}
这种做法保证了现将buffer构造好string,随后线程传递的时候传递string就不会有这个问题。

2.传递引用时无法修改引用的数据

void update_data_for_widget(widget_data& data);//函数接受的参数是引用
void oops_again()
{
    widget_data data;
    std::thread t(update_data_for_widget,data);//试图在异步线程中修改data
    t.jion();
   process_widget(data);
}
虽然update_data_for_widget这个函数接受的是引用,可以修改data的值。但是当我们把data传入std::thread的构造函数时,拷贝构造就已经发生了。也就是说,最后update_data_for_widget这个函数处理的只是一份拷贝,根本就不会修改原始的值。所以在这种场景下,我们可以采用以std::ref的形式传递引用。相当于在引用上面做了一层对象封装,单纯的传递对象依旧可以修改原始的值:

std:thread t(update_data_for_widget,std::ref(data));

另外,线程如果像传递一个成员函数作为参数,其形式类似于bing的形式:

class X
{
    public:
        void do_lengthy_work();
}
x my_x;
std::thread t(&X::do_lengthy_work,&my_x);
对于参数有std::move的需求,对于临时变量将会自动调用,对于有名字的变量我们可以采用std::move()来要求执行。

同样的,std::thread对象是一个只可以移动,不可以拷贝的对象。这里注意一个场景:如果一个对象已经被初始化后,又被赋予其他的对象,就会产生问题:

	std::thread t1(test_function);
	std::thread t2(test_function);
	t1 = std::move(t2);
这里执行的第三句是程序就会异常退出,因为t1已经有了对象并且在释放这个线程前没有调用任何的detach() or join().



  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值