对于一个非常简单的测试示例,当尝试在OpenMP构造中填充Eigen::SparseMatrix
时,应用程序崩溃。
SparseMatrix<double> A_mat( nCol, nRow );
//A_mat.reserve( VectorXi::Constant( nCol, nRow ) ); // When commented crashes
auto numThreads = omp_get_max_threads();
#pragma omp parallel for num_threads( numThreads )
for ( int j = 0; j < nCol; ++j )
{
for ( int i = 0; i < nRow; ++i )
{
if ( i >= j )
{
double val = i * nCol + j;
A_mat.insert( i, j ) = val;
}
}
}
仅当我使用1
线程时,此代码才能按预期运行。但是,当使用多个线程运行时,会引发以下错误:
double free or corruption (!prev)
double free or corruption (!prev)
double free or corruption (!prev)
double free or corruption (top)
double free or corruption (!prev)
double free or corruption (out)
当我取消注释以下行时:
A_mat.reserve( VectorXi::Constant( nCol, nRow ) );
然后,即使在具有多个线程的情况下,上述给定的代码块也再次产生预期的结果。
有人可以向我解释为什么会这样吗?
答案 0 :(得分:3)
无需进一步研究SparseMatrix
,当添加的元素超出其容量时,几乎可以肯定,它必须(重新)分配内存。这不是线程安全的操作,因此,除非知道不会重新分配元素,否则请勿同时向SparseMatrix
添加元素。即使那样,您也应该检查文档以验证这样做是否是线程安全的,因为对此我有疑问(但也许可以同时插入不同的列或行中也可以)。即使它不安全,它也可能不会崩溃,只是做错了事(即未定义的行为)。
为记录起见,这类似于std::vector
的行为。以向量重新分配的方式同时调用push_back
是重新分配的竞争条件,因此是未定义的行为(并且将迅速导致双重释放,如您所见)。 [当然,插入本身也会有一个竞争条件,SparseMatrix
可能会也可能不会避免在不同坐标处同时插入,但我不会打赌。] < / p>