#include <iostream> #include<thread> using namespace std; void ThreadFun(const int &arr1,char *pBuf) { cout << arr1 << endl; cout << pBuf << endl; return; } int main() { int temp = 10; char arr[20] = "Hello Word"; std::thread t1(ThreadFun, temp,arr); t1.detach(); std::cout << "主线程运行 "; }
以上代码有2个误区,
误区1:大家会认为线程函数第一个参数是引用,线程用的是detach(),则会出现一种问题,就是当主线程退出时,temp变量释放掉了,子线程的第一个参数是引用,所以地址也被释放掉了,而线程函数里面还用到了这个参数,就会出现用了已经释放的地址的问题,这种想法是错的。
解释:线程函数第一个参数使用的是引用(&arr1),但是实际调试时,它与调用时传进来的实参(temp)的地址不同,则表示它线程函数第一个参数不是实际的引用,是假的引用,只是做了个值的拷贝,所以不会出现用了已经释放的地址的问题。
线程函数第二个参数是指针,调试时发现地址实参和形参的地址相同,则指传参是有问题的,会出现用了已经释放的地址的问题,不建议使用指针。
误区2:大家会认为第二个参数不让使用指针,但是我也传字符串那我可以这样写,
#include <iostream> #include<thread> using namespace std; void ThreadFun(const int &arr1,string &pBuf) { cout << arr1 << endl; cout << pBuf.c_str() << endl; return; } int main() { int temp = 10; char arr[20] = "Hello Word"; std::thread t1(ThreadFun, temp,arr); t1.join(); std::cout << "主线程运行 "; }
以上的写法形参和实参的地址不同,看起来没啥问题,但是实际也是错误的,这样写会出现一个问题,就是从代码上看线程函数开始前arr实参是被隐式转换为了string,
但是程序不确定啥时去转换,调试时有这种可能,就是主线程都退出了,arr还没有被转换为string,此时,主线程退出,arry被释放掉了,现在要把现在就相当与把一块不确定的地址转换为string,这是不对的。正确的使用方法,就是在传参的时候把arr强制转换为临时的string类型传递给线程就不会出现上面的问题。例如:
std::thread t1(ThreadFun, temp,string(arr));