-2

For a very simple test example when trying to fill Eigen::SparseMatrix within OpenMP construct, application crashes.

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;
                    }
            }
    }

This code runs how expected only when I use 1 thread. However, when run with multiple threads following errors are thrown:

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)

When I uncomment the following line:

A_mat.reserve( VectorXi::Constant( nCol, nRow ) );

then above given block of code again produces expected results even when run with multiple threads.

Could someone explain to me why is this happening?

Karpov
  • 1
  • 1
  • 3

1 Answers1

3

Without looking further into SparseMatrix, it almost definitely has to (re-)allocate memory when you add more elements than it has capacity. This is not a thread-safe operation, thus you should never concurrently add elements to a SparseMatrix unless you know it won't reallocate. Even then, you should check the documentation to verify that doing this is thread-safe, because I have my doubts about that (but maybe inserting into different columns or rows concurrently may be ok). Even if it is unsafe, it may not crash but just do wrong things (i.e. undefined behavior).

For the record, this is similar to how std::vector behaves. Calling push_back concurrently in such a way that the vector reallocates is a race condition on the reallocation and thus undefined behavior (and will quickly lead to double frees like you are seeing). [There would of course also be a race condition on the insertion itself, which SparseMatrix may or may not avoid for concurrent insertions at different coordinates, but I would not bet on it.]

Max Langhof
  • 23,383
  • 5
  • 39
  • 72