Search code examples
c++qtopenmpqmapqvector

error acessing and editing a Qmap from inside a OpenMP loop


I am doing a loop for with openmp in c++ to feed some values inside a QMAP from a QVector and in some computers it says "program stopped to work" but in some computers it works.

I saw that Qmap is not thread safe however I need a container with tags (because of that I use a Qmap) to input the results from an inside calculation and use it later in a serial part of the code.

an example of my code is as follows: Being mystringlist a QString, themaps is a QMap<QString, QMap<int, QVector<float>>> and myvector a QVector<float>.

#pragma omp parallel for  schedule(static) num_threads(std::thread::hardware_concurrency())
 for (int i = 0; i < numb_of_iter; i++) 
{
   for each (auto var in mystringlist)
   {
       for (int j = 0; j < 33; j++)
       {
           themaps[var][i] << std::log10(j+1) + myvector[i]; 
       }
    }
}

in serial mode this code works, however in a parallel block sometimes it crashes. So my idea is if there is a method to allow all threads to acess this variable themaps so it wont crash because they wont try to write in the same memory space, each one has its own i so they should be able to do that. I do not know another option to do that because I need to use this variable themaps later on the code.


Solution

  • The sane solution: Protect your shared variables via a mutex. You of course pay a performance penalty for that, which is only acceptable if the calculation of the new value takes much longer than the insertion into your data structure.

    The bold solution: Preallocate all fields so that the data structure doesn't change because of the insertions.

    You'd need to consider two effects:

    1. If you access a QMap key that doesn't exist, a new field will be created. The map will detach. This will change the internal data layout.
    2. If you access the map with a non-const method, the map will detach, too, if you have more than one reference to it (Qt's copy-on-write idiom).

    For QVector, that's simple with QVector::resize(n). After this, you can set any field value within [0..n-1] as long as no one else reads or writes to that field at the same time.

    QMap is a different beast. Avoid, if possible.
    (Just a hint: Only the iterators guarantee not to return a copy of the item.)