Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parallelize a plain for loop using the C++ standard library

I feel kind of dumb having to ask this, but I just can't find a non-convoluted way to do this.

I have the following loop:

for (int i = 0; i < count; ++i) {
  if (myFunc(i))
    continue;

  myOtherFunc(i);
}

Parallelizing this with OpenMP is trivial: Just add #pragma omp parallel for before the loop.

I wanted to compare the performance of OMP (and its different schedules) to MSVC's parallel <algorithms> implementation (i.e. using C++17 execution policies). The straightforward idea would be to use std::for_each, but I can't figure out a good way to transform this super plain for loop into any appropriate <algorithm> thing that I can throw an execution policy at.

Notably, you can't just do

std::for_each(std::execution::par, 0, count, [](int i){ /*...*/ });

because you must supply iterators (i.e. something that yields the i argument when dereferenced).

  • I could std::iota into a std::vector of int just so I have a range of indices to iterate over. That would be absurd though.

  • I could use std::generate_n with some dummy output iterator that discards whatever it is assigned. Since I don't think that's available in std I would have to write the full dummy iterator myself. And this would of course be a stupid hack regardless. And getting a hold of the correct index would probably require manual tracking with a std::atomic<int> because you don't get to know your current index.

  • I really don't have a container to loop over. I mean, somewhere deep inside those functions there are containers, but restructuring everything just so I can use iterators over some container in this loop is out of the question.

  • 15 minutes of googling different descriptions of this didn't get me anywhere.

Is there some way to match the most plain and basic for loop with <algorithm> tools that doesn't involve silly nonsense?

like image 740
Max Langhof Avatar asked Apr 25 '19 09:04

Max Langhof


1 Answers

If using boost, you may use the boost::irange (in boost-range) to produce the counting loop like this:

auto ints = boost::irange(0, count);
std::for_each_n(POLICY, ints.begin(), boost::size(ints), [](int i)
{
  if (!myFunc(i)) {
    myOtherFunc(i);
  }
}
);
like image 141
darune Avatar answered Oct 23 '22 04:10

darune