С++: контейнеры STL OpenMP и не-произвольного доступа - возможное обходное решение

Итак, на SO и в Интернетах в целом существует много путаницы и разочарования в отношении того, как сделать простые в использовании директивы #pragma OpenMP совместимыми с С++ одинаково удобными контейнерами STL.

Все говорят об обходах для STL vector, но как насчет контейнеров с неважным доступом/двунаправленности, таких как map, list, set и т.д.?

Я столкнулся с этой проблемой и разработал очень простой, очевидный способ обхода. Я представляю его здесь для STL map, но он явно обобщается.

Последовательная версия:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
    { /* do work with  it   */  }

Мое предлагаемое решение для использования OpenMP с STL map:

    //make an array of iterators.
    int loop_length = my_map.size();
    std::map<A,B>::iterator loop_array[ loop_length ];

    std::map<A,B>::iterator allocate_it = my_map.begin();
    for (int j=0; j<loop_length; ++j)
        loop_array[j] = allocate_it++;

    // now you can use OpenMP as usual:
    #pragma omp parallel for
    for (uint j=0; j<loop_length; ++j) 
       { /* do work with    loop_array[j]    */  }

Я далек от эксперта по OpenMP, поэтому Я хотел бы знать, эффективна ли моя предлагаемая рабочая обстановка и хорошая практика.

Предположим, что программист отвечает за потокобезопасную обработку контейнера STL в цикле for.

Наконец, мое предложенное решение более эффективно, чем следующее общепринятое решение (см. ответ на этот вопрос SO), потому что в моем решении каждый поток не перебирать весь контейнер?

#pragma omp parallel
{
    for (std::map<A,B>::iterator it = my_map.begin();
            it != my_map.end();
            ++it) 
    #pragma single nowait
       {   /*  do work  */   }

}

Ответ 1

OpenMP предоставляет конструкцию task, начиная с версии 3.0, которая весьма полезна для использования с STL:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
{
   #pragma omp task
   { /* do work with  it   */  }
}

Конечно, зависимости между итерациями не должны существовать для этого.