Partager via


Comment : convertir une boucle OpenMP parallèle pour utiliser le runtime d’accès concurrentiel

Cet exemple montre comment convertir une boucle de base qui utilise le parallèle OpenMP et pour les directives pour utiliser l’algorithme Concurrency Runtime concurrency ::p arallel_for.

Exemple : nombre d’éléments premiers

Cet exemple utilise OpenMP et le runtime d’accès concurrentiel pour calculer le nombre de nombres premiers dans un tableau de valeurs aléatoires.

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

Cet exemple produit la sortie suivante.

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

L’algorithme parallel_for et OpenMP 3.0 permettent au type d’index d’être un type intégral signé ou un type intégral non signé. L’algorithme parallel_for garantit également que la plage spécifiée ne dépasse pas un type signé. OpenMP versions 2.0 et 2.5 autorisent uniquement les types d’index intégral signés. OpenMP ne valide pas non plus la plage d’index.

La version de cet exemple qui utilise le runtime d’accès concurrentiel utilise également un objet concurrency ::combinable à la place de la directive atomique pour incrémenter la valeur de compteur sans nécessiter de synchronisation.

Pour plus d’informations sur parallel_for et d’autres algorithmes parallèles, consultez Algorithmes parallèles. Pour plus d’informations sur la combinable classe, consultez Conteneurs et objets parallèles.

Exemple : utiliser std ::array

Cet exemple modifie le précédent pour agir sur un objet std ::array au lieu d’un tableau natif. Étant donné que les versions 2.0 et 2.5 d’OpenMP autorisent uniquement les types d’index intégral signés dans une parallel_for construction, vous ne pouvez pas utiliser d’itérateurs pour accéder aux éléments d’un conteneur de bibliothèque standard C++ en parallèle. La bibliothèque de modèles parallèles (PPL) fournit l’accès concurrentiel ::p arallel_for_each , qui effectue des tâches, en parallèle, sur un conteneur itératif tel que ceux fournis par la bibliothèque standard C++. Il utilise la même logique de partitionnement que celle utilisée par l’algorithme parallel_for . L’algorithme parallel_for_each ressemble à l’algorithme std ::for_each de la bibliothèque standard C++, sauf que l’algorithme parallel_for_each exécute les tâches simultanément.

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

Compilation du code

Copiez l’exemple de code et collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé concrt-omp-count-primes.cpp , puis exécutez la commande suivante dans une fenêtre d’invite de commandes Visual Studio.

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

Voir aussi

Migration d’OpenMP au runtime d’accès concurrentiel
Algorithmes parallèles
Conteneurs et objets parallèles