c++线程,除了可以利用普通函数创建线程外,还有其他创建线程的方法:
具体使用方法如下:
#include
using namespace std;
class TA
{
public:
void operator ()()
{
printf("%s", "线程开始执行 \n");
}
};
void main()
{
TA ta;
// thread 方法会调用TA的拷贝构造函数,所以使用detach方法,只要TA对象里没有引用和指针,就不会产生问题
thread mThreadObj(ta);
if (mThreadObj.joinable())
mThreadObj.join();
auto mLambdaThreaadObj = []
{
printf("%s", "线程开始执行 \n");
};
thread m_LambdaThread(mLambdaThreaadObj);
if (m_LambdaThread.joinable())
m_LambdaThread.join();
}
补充内容:
thread 方法会调用TA的拷贝构造函数,所以使用detach方法,只要TA对象里没有引用和指针,就不会产生问题,否则一旦传入主线程中的临时变量,并且主线程先于子线程执行完毕(可能会发生这种情况),那么程序运行情况就不可知,这是一定要避免的。
首先,观察如下案例:
void mPrint(const int& i, char* pmBuff)
{
printf("i : %d, buff: %s \n", i, pmBuff);
}
void main()
{
int mI = 1;
int& mIy = mI;
char mBuff[]= "this is a test";
thread mThread(mPrint,mI, mBuff);
mThread.join();
}
在mThread线程中,我传入了两个局部变量,并且接收函数中有两个参数,一个是引用类型,一个是指针类型。
如果我将线程的控制由join变为detach会引发什么问题?
很容易想到的是,因为主线程和子线程的结束时间不可控,所以局部变量的销毁时间不可控,那程序的运行情况就是未知的。再细究,这里由两个参数,是两个参数都会受影响,还是其中一个,又可能是哪一个?
可以看到,引用类型的参数内存地址和主线程中不一样,指针类型的参数和主线程中的一样。因此可以得到结论,如果线程中的形参是引用类型,那主线程会将传入的值做一次赋值,所以不是真的直接引用绑定,但是如果形参是指针类型,那就不会拷贝。
但如何避免这种情况呢?
我起初的思路是,只要再参数传递过程中,产生了拷贝那就是安全的(并不正确),因此我总结了c++中会调用拷贝构造函数的三种情形:
这里适用的就是第二种情况。
但是,我又反应过来,这个拷贝构造函数发生的时间是在主线程之前还是之后呢?如果是在主线程结束之后才调用,那detach的风险并没有规避掉,因此我又做了如下尝试:
#include
using namespace std;
class TA
{
public:
int m_i;
TA(const int& i) :m_i(i)
{
printf("%s", "拷贝构造函数执行 \n");
};
void operator ()()
{
printf("%s", "线程开始执行 \n");
}
};
void mPrint( char* pmBuff,const TA&ta)
{
printf("i : %d, buff: %s \n",ta.m_i, pmBuff);
}
void main()
{
int mI = 1;
int& mIy = mI;
char mBuff[]= "this is a test";
//利用类型转化构造函数将整型转成TA类型
thread mThread(mPrint, mBuff,mI);
mThread.detach();
}
因为thread肯定会调用传入对象的拷贝构造函数,所以如果输出中没有显示拷贝构造函数的执行,那么就说明,拷贝可能发生在主线程结束之后。
执行结果:
结论:
这样也是不安全的。
那究竟如何解决detach的这个隐患呢?
通过翻阅资料发现,只需使用临时对象即可完美规避这个问题。
如下所示:
thread mThread(mPrint, mBuff,TA(mI));
1、如果传递简单类型参数,使用值传递,不要使用引用传递,杜绝使用指针传递;
2、如果传递类对象,在创建线程时就构造临时对象,在函数参数里,使用引用来接 。
(建议一律使用join,能避免90%的问题)
以上就是本篇文章的全部内容,如果不足,请批评指正。
本文转载自:深入理解c++多线程:(一)detach使用隐患
参考文章:C++ thread detach的大坑