我正在尝试将一系列参数传递给不同的c ++线程。当NumThreads == 1时程序运行正常,但是当NumThreads> 1,线程中传递给函数的p参数不正确。我是否在线程构造函数中遗漏了某些内容而没有通过值传递p?
创建线程的位置:
int NumThreads = 2;
std::thread t[numSamplePoints];
std::mutex dataLock;
for( int i = 0 ; i < numSamplePoints ; i++)
{
// Prevent more than NumThreads from running at once
if( i > NumThreads && t[i-NumThreads].joinable() )
{
t[i - this->NumThreads].join();
}
// Set and Check Input Parameters
double p[3];
srcPoints->GetPoint(i , p);
if( i < 3 )
{
cout<< "OUTTHREAD " << p[0] << " " << p[1] << " " << p[2] <<endl;
cout<< "src: " << Id << " index: " << i <<endl;
}
t[i] = std::thread(&MyClass::MyFunction, this, &dataLock, i, Id, p);
}
调用成员函数:
void MyClass::MyFunction(std::mutex *dataLock, int sampleIndex, int Id, double srcPoint[3])
{
dataLock->lock();
if( sampleIndex < 3)
{
cout<< "IN THREAD " << srcPoint[0] << " " << srcPoint[1] << " " << srcPoint[2] <<endl;
cout<< "src: " << sourceId << " index: " << sampleIndex <<endl;
}
dataLock->unlock();
}
前三个主题的控制台输出: {
OUTTHREAD 45.7694 1.06209 -60.9628
src: 0 index: 0
OUTTHREAD 48.6044 -5.40514 -54.7663
src: 108 index: 1
OUTTHREAD 52.505 9.00298 -47.0499
src: 216 index: 2
IN THREAD 52.505 9.00298 -47.0499
src: 0 index: 0
IN THREAD 52.505 9.00298 -47.0499
src: 108 index: 1
IN THREAD 52.505 9.00298 -47.0499
src: 216 index: 2
因此ID和样本索引正确地传递给线程,但是srcPoint对于所有三个线程是如何相同的?!?
答案 0 :(得分:1)
通过将指向局部变量的指针传递给线程并允许变量在使用之前超出范围来调用未定义的行为。
C风格的数组永远不会按值传递。声明为将数组类型作为参数的函数实际上需要一个指针:
void MyClass::MyFunction(std::mutex *dataLock, int sampleIndex, int Id, double srcPoint[3])
相当于
void MyClass::MyFunction(std::mutex *dataLock, int sampleIndex, int Id, double* srcPoint)
在这种情况下,您的p
数组是for
循环范围的本地数组,当它传递给thread
构造函数时,它隐式地衰减为指向其第一个元素的指针。一旦循环的每次迭代完成,p
超出范围并被销毁,但是你的线程仍然有一个指向它曾经存在的内存的指针。
解决此问题的最佳方法是在循环中将double p[3]
替换为std::array<double, 3> p
,并使MyClass::MyFunction
取代std::array<double, 3> srcPoint
而不是double srcPoint[3]
。与原始C样式数组不同,std::array
可以通过值传递,并实现您期望的复制语义。