带有 OpenMP 的特征稀疏矩阵 - 插入值时崩溃

Eigen SparseMatrix with OpenMP - crash when inserting values

本文关键字:插入 崩溃 OpenMP 特征 带有      更新时间:2023-10-16

对于一个非常简单的测试示例,当尝试在 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 ) );

然后上面给定的代码块再次产生预期的结果,即使使用多个线程运行也是如此。

有人可以向我解释为什么会发生这种情况吗?

在不进一步研究SparseMatrix的情况下,当您添加的元素多于容量时,它几乎肯定必须(重新(分配内存。这不是线程安全操作,因此切勿同时向SparseMatrix添加元素,除非您知道它不会重新分配。即便如此,您也应该检查文档以验证这样做是线程安全的,因为我对此表示怀疑(但也许同时插入到不同的列或行中可能是可以的(。即使不安全,它也可能不会崩溃,而只是做错事(即未定义的行为(。

为了记录,这类似于std::vector的行为方式。以向量重新分配的方式并发调用push_back是重新分配的竞争条件,因此是未定义的行为(并且会很快导致您所看到的双重释放(。[当然,插入本身也会有一个竞争条件,对于不同坐标的并发插入,SparseMatrix可能会也可能不会避免这种情况,但我不会打赌。