detach收尾时传递临时对象作为线程参数

//一般情况下,我们使用join()收尾不会显得那么复杂

  1 #include<iostream>                                                          
  2 #include<thread>
  3 using namespace std;
  
  4 void fun(const int &v,char*buff)
  5 {
  6     cout<<v<<endl;
  7     cout<<buff<<endl;
  8 }
  9 int main()
 10 {
 11     int val = 100;
 12     int &re = val;
 13     char buf[] = "hello world";
 14     thread t(fun,re,buf);
 15     //第一个参数为线程执行的函数,后面依次是函数的参数
 16     t.join();
 17     cout<<"main thred quit"<<endl;
 18     return 0;
 19 }

一.传递临时对象作为线程参数,而不是指针

当我们使用的是detach()来作为整个进程的收尾,如果我们参数传递引用或者指针
会有什么问题?
  1 #include<iostream>
  2 #include<thread>
  3 using namespace std;
  4 
  5 void fun(const int &v,char*buff)
  6 {   
  7     cout<<v<<endl;                                                          
  8     cout<<buff<<endl;
  9 }   
 10 int main()
 11 {
 12     int val = 100;
 13     int &re = val;
 14     char buf[] = "hello world";
 15     thread t(fun,re,buf);
 16     t.detach();
 17     cout<<"main thread quit"<<endl;
 18     return 0;
 19 }   
 运行多次的结果,如下:
txp@txp-TM1801:~/mydir/study_note/0720$ ./2
main thread quit
100
hello wo
hello wo
txp@txp-TM1801:~/mydir/study_note/0720$ ./2
main thread quit
100
hello wo
txp@txp-TM1801:~/mydir/study_note/0720$ ./2
main thread quit
txp@txp-TM1801:~/mydir/study_note/0720$ ./2
main thread quit
100
hello wo

我们分析一下,为什么会有这样的结果,可能出现问题是哪一部分?

1.
实际上,我们可以通过打印变量地址查看val re v三个变量及形参的地址
&val = &re != v,也就是说传递给线程函数的v不是主线程中那个变量,
而是thread()在内部在传递引用的时候对引用中数据进行了拷贝,所以1打印100的值没什么问题.
2.
查看实参buf和形参buf的地址值,发现是相等,也就是说,主线程将子线程分离出去以后
在子线程的执行函数中,使用的buf是主线程的buf,可是这个时候主线程很有可能已经执行完毕
释放了buf这块内存,所以才会出现问题.

总结一下:detach() :

  1. 在thread()给子线程函数传递参数时,如果使用引用,内部会讲这个引用指向的内存中的东西拷贝到子线程的内存中,所以使用引用一般不会有什么问题;
  2. 但是,使用指针却不一样,是直接将主线程这块内存的地址传递给子线程函数,并不会像引用一样会进行内存中内容的拷贝,所以,使用detach()一定不能使用指针作为参数;

那么如何解决不能使用传递指针和避免使用引用的问题: 传递临时对象

在以前写C++代码时,都是时刻避免临时对象的产生,因为影响效率,
但是这里就有点特殊,给子线程函数传递参数的时候使用临时对象,而不是引用或者指针.buhuishixiao

解决方案一:
实参传递一个字符串,形参用const string &buf接受,这样就会构造一个string对象,
即使主线程退出,子线程访问字符串也是自己在子线程的内存上.
void fun(const int &v,const string &buff)
 {   
    cout<<v<<endl;                                                          
     cout<<buff.c_str()<<endl;
 }   
 //...
  thread t(fun,re,buf);
  //...
 问题:
 执行到 thread t(fun,re,buf)时,buf是什么时候开始转换成string的
 也就是存在,buf都被回收了,才开始转换成string的操作这个问题
 即main都执行完了,buf内存都回收了,才开始转换,那么访问这块内存一定是有问题的
 

也就是说,解决方案一也是存在问题的,也是一个BUG,解决方案二:

传递实参的时候,就将参数转换成临时对象,然后进行传递
void fun(const int &v,const string &buff)
 {   
    cout<<v<<endl;                                                          
     cout<<buff.c_str()<<endl;
 }   
 //...
  thread t(fun,re,string(buf));
  t.detach();
  //...
传递临时对象的字面值,即string(buf),在主线程执行完毕之前就将对象拷贝到子线程函数中

总结:
在创建线程的的同时,创建参数的临时对象进行传递参数方式是可行的.
用临时对象给子线程函数传递参数,就一定可以在detach后成功正确的使用参数内存,变量就不会失效,主线程退出后变量不会失效.

建议:
对于传递简单的int这样的类型,建议直接使用字面值传递.;
如果传递对象,避免隐士的类型转换,全部在创建线程thread()这行代码中将临时对象构建出来
形参接受的时候使用引用

如果使用join()就不存在这些问题了.
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值