How to: Convert an OpenMP Loop that Uses a Reduction Variable to Use the Concurrency Runtime
This example demonstrates how to convert an OpenMP parallelfor loop that uses the reduction clause to use the Concurrency Runtime.
The OpenMP reduction clause lets you specify one or more thread-private variables that are subject to a reduction operation at the end of the parallel region. OpenMP predefines a set of reduction operators. Each reduction variable must be a scalar (for example, int, long, and float). OpenMP also defines several restrictions on how reduction variables are used in a parallel region.
The Parallel Patterns Library (PPL) provides the concurrency::combinable class, which provides reusable, thread-local storage that lets you perform fine-grained computations and then merge those computations into a final result. The combinable class is a template that acts on both scalar and complex types. To use the combinable class, perform sub-computations in the body of a parallel construct and then call the concurrency::combinable::combine or concurrency::combinable::combine_each method to produce the final result. The combine and combine_each methods each take a combine function that specifies how to combine each pair of elements. Therefore, the combinable class is not restricted to a fixed set of reduction operators.
Example
This example uses both OpenMP and the Concurrency Runtime to compute the sum of the first 35 Fibonacci numbers.
// concrt-omp-fibonacci-reduction.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <iostream>
using namespace concurrency;
using namespace std;
// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
if (n < 2)
return n;
// Compute the components in parallel.
int n1, n2;
parallel_invoke(
[n,&n1] { n1 = fibonacci(n-1); },
[n,&n2] { n2 = fibonacci(n-2); }
);
return n1 + n2;
}
// Uses OpenMP to compute the sum of Fibonacci numbers in parallel.
void omp_parallel_fibonacci_sum(int count)
{
int sum = 0;
#pragma omp parallel for reduction(+ : sum)
for (int i = 0; i < count; ++i)
{
sum += fibonacci(i);
}
wcout << L"The sum of the first " << count << L" Fibonacci numbers is "
<< sum << L'.' << endl;
}
// Uses the Concurrency Runtime to compute the sum of Fibonacci numbers in parallel.
void concrt_parallel_fibonacci_sum(int count)
{
combinable<int> sums;
parallel_for(0, count, [&sums](int i)
{
sums.local() += fibonacci(i);
});
wcout << L"The sum of the first " << count << L" Fibonacci numbers is "
<< sums.combine(plus<int>()) << L'.' << endl;
}
int wmain()
{
const int count = 35;
wcout << L"Using OpenMP..." << endl;
omp_parallel_fibonacci_sum(count);
wcout << L"Using the Concurrency Runtime..." << endl;
concrt_parallel_fibonacci_sum(count);
}
This example produces the following output.
Using OpenMP... The sum of the first 35 Fibonacci numbers is 14930351. Using the Concurrency Runtime... The sum of the first 35 Fibonacci numbers is 14930351.
For more information about the combinable class, see Parallel Containers and Objects.
Compiling the Code
Copy the example code and paste it in a Visual Studio project, or paste it in a file that is named concrt-omp-fibonacci-reduction.cpp and then run the following command in a Visual Studio Command Prompt window.
cl.exe /EHsc /openmp concrt-omp-fibonacci-reduction.cpp