带有 OpenMP 的 Eigen SparseMatrix - 插入值时崩溃

Eigen SparseMatrix with OpenMP - crash when inserting values

对于一个非常简单的测试示例,当尝试在 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可能会或可能不会避免在不同坐标处的并发插入,但我不会打赌。]