Condividi tramite


Procedura: convertire un ciclo OpenMP parallel for per l'utilizzo del runtime di concorrenza

In questo esempio viene illustrato come convertire un ciclo di base che utilizza le direttive parallel e for di OpenMP per utilizzare l'algoritmo Concurrency::parallel_for del runtime di concorrenza.

Esempio

In questo esempio vengono utilizzati sia OpenMP che il runtime di concorrenza per calcolare il conteggio dei numeri primi in una matrice di valori casuali.

// 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;
}

Questo esempio produce l'output che segue.

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

L'algoritmo parallel_for e OpenMP 3.0 consentono che il tipo di indice sia un tipo integrale con segno oppure un tipo integrale senza segno. L'algoritmo parallel_for assicura inoltre che l'intervallo specificato non superi un tipo con segno. Nelle versioni 2.0 e 2.5 di OpenMP sono consentiti solo tipi di indice integrali con segno. OpenMP inoltre non convalida l'intervallo dell'indice.

Nella versione di questo esempio in cui si utilizza il runtime di concorrenza si utilizza anche l'oggetto Concurrency::combinable in luogo della direttiva atomic per incrementare il valore del contatore senza richiedere la sincronizzazione.

Per ulteriori informazioni su parallel_for e altri algoritmi paralleli, vedere Algoritmi paralleli. Per ulteriori informazioni sulla classe combinable, vedere Contenitori e oggetti paralleli.

In questo esempio viene modificato l'esempio precedente in modo che si possa agire su un oggetto std::array anziché su una matrice nativa. Poiché nelle versioni 2.0 e 2.5 di OpenMP sono consentiti solo tipi di indice integrali con segno in un costrutto parallel for, non è possibile utilizzare gli iteratori per accedere agli elementi di un contenitore STL (Standard Template Library) in parallelo. Nella libreria PPL (Parallel Patterns Library) è disponibile l'algoritmo Concurrency::parallel_for_each, che esegue attività, in parallelo, su un contenitore iterativo come quelli forniti dal contenitore STL. Utilizza la stessa logica di partizionamento utilizzata dall'algoritmo parallel_for. L'algoritmo parallel_for_each è simile all'algoritmo std::for_each STL, con l'unica differenza che l'algoritmo parallel_for_each esegue le attività simultaneamente.

// 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(a.begin(), a.end(), [&counts](int n) 
   {
      if (is_prime(n)) {
         counts.local()++;
      }
   });

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

Compilazione del codice

Copiare il codice di esempio e incollarlo in un progetto Visual Studio oppure incollarlo in un file denominato concrt-omp-count-primes.cpp, quindi eseguire il comando seguente in una finestra del prompt dei comandi di Visual Studio 2010.

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

Vedere anche

Concetti

Algoritmi paralleli

Contenitori e oggetti paralleli

Altre risorse

Migrazione da OpenMP al runtime di concorrenza