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 */ }
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With