Redigera

Dela via


How to: Convert an OpenMP parallel for Loop to Use the Concurrency Runtime

This example demonstrates how to convert a basic loop that uses the OpenMP parallel and for directives to use the Concurrency Runtime concurrency::parallel_for algorithm.

Example - prime count

This example uses both OpenMP and the Concurrency Runtime to compute the count of prime numbers in an array of random values.

// concrt-omp-count-primes.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <random>
#include <array>
#include <iostream>

using namespace concurrency;
using namespace std;

// Determines whether the input value is prime.
bool is_prime(int n)
{
   if (n < 2)
      return false;
   for (int i = 2; i < n; ++i)
   {
      if ((n % i) == 0)
         return false;
   }
   return true;
}

// Uses OpenMP to compute the count of prime numbers in an array.
void omp_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   size_t count = 0;
   #pragma omp parallel for
      for (int i = 0; i < static_cast<int>(size); ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an array.
void concrt_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   combinable<size_t> counts;
   parallel_for<size_t>(0, size, [&](size_t i) 
   {
      if (is_prime(a[i])) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

int wmain()
{
   // The length of the array.
   const size_t size = 1000000;
   
   // Create an array and initialize it with random values.
   int* a = new int[size];
   
   mt19937 gen(42);
   for (size_t i = 0; i < size; ++i) {
      a[i] = gen();
   }

   // Count prime numbers by using OpenMP and the Concurrency Runtime.

   wcout << L"Using OpenMP..." << endl;
   omp_count_primes(a, size);

   wcout << L"Using the Concurrency Runtime..." << endl;
   concrt_count_primes(a, size);

   delete[] a;
}

This example produces the following output.

Using OpenMP...
found 107254 prime numbers.
Using the Concurrency Runtime...
found 107254 prime numbers.

The parallel_for algorithm and OpenMP 3.0 allow for the index type to be a signed integral type or an unsigned integral type. The parallel_for algorithm also makes sure that the specified range does not overflow a signed type. OpenMP versions 2.0 and 2.5 allow for signed integral index types only. OpenMP also does not validate the index range.

The version of this example that uses the Concurrency Runtime also uses a concurrency::combinable object in place of the atomic directive to increment the counter value without requiring synchronization.

For more information about parallel_for and other parallel algorithms, see Parallel Algorithms. For more information about the combinable class, see Parallel Containers and Objects.

Example - use std::array

This example modifies the previous one to act on an std::array object instead of on a native array. Because OpenMP versions 2.0 and 2.5 allow for signed integral index types only in a parallel_for construct, you cannot use iterators to access the elements of a C++ Standard Library container in parallel. The Parallel Patterns Library (PPL) provides the concurrency::parallel_for_each algorithm, which performs tasks, in parallel, on an iterative container such as those provided by the C++ Standard Library. It uses the same partitioning logic that the parallel_for algorithm uses. The parallel_for_each algorithm resembles the C++ Standard Library std::for_each algorithm, except that the parallel_for_each algorithm executes the tasks concurrently.

// Uses OpenMP to compute the count of prime numbers in an 
// array object.
template<size_t Size>
void omp_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   size_t count = 0;
   int size = static_cast<int>(a.size());
   #pragma omp parallel for
      for (int i = 0; i < size; ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an 
// array object.
template<size_t Size>
void concrt_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   combinable<size_t> counts;
   parallel_for_each(begin(a), end(a), [&counts](int n) 
   {
      if (is_prime(n)) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

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-count-primes.cpp and then run the following command in a Visual Studio Command Prompt window.

cl.exe /EHsc /openmp concrt-omp-count-primes.cpp

See also

Migrating from OpenMP to the Concurrency Runtime
Parallel Algorithms
Parallel Containers and Objects