//一般情况下,我们使用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() :
- 在thread()给子线程函数传递参数时,如果使用引用,内部会讲这个引用指向的内存中的东西拷贝到子线程的内存中,所以使用引用一般不会有什么问题;
- 但是,使用指针却不一样,是直接将主线程这块内存的地址传递给子线程函数,并不会像引用一样会进行内存中内容的拷贝,所以,使用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()就不存在这些问题了.