Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++: OpenMP and non-random-access STL containers - a possible workaround

So on SO, and the Internets in general, there is much confusion and frustration about how to make OpenMP's easy-to-use #pragma directives cooperate with C++'s equally easy-to-use STL containers.

Everyone talks about work-arounds for STL vector, but what about non-random access / bi-directional containers, like map, list, set, etc. ?

I encountered this problem and devised a very simple, obvious workaround. I present it here for STL map, but it is clearly generalizable.

Serial version:

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

My proposed solution to use OpenMP with 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]    */  }

I am far from an expert on OpenMP, however, so I would like to know if my proposed work-around is efficient and good practice.

Please assume that the programmer is responsible for thread-safe handling of the STL container within the for loop.

Finally, is my proposed solution more efficient than the following commonly-proposed solution (see answer to this SO Question), because, in my solution,each thread does not iterate over the whole container?

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

}
like image 514
cmo Avatar asked May 03 '12 14:05

cmo


1 Answers

OpenMP provides the task construct starting with version 3.0 which is quite useful for use with STL:

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

Of course, data dependencies between iterations should not exist for this to work.

like image 129
Hristo Iliev Avatar answered Nov 15 '22 16:11

Hristo Iliev