Condividi tramite


Procedura: convertire un ciclo OpenMP che utilizza l'annullamento per l'utilizzo del runtime di concorrenza

Alcuni cicli paralleli non richiedono l'esecuzione di tutte le iterazioni.Ad esempio, un algoritmo che cerca un valore può terminare dopo che il valore è stato trovato.OpenMP non fornisce un meccanismo per uscire da un ciclo parallelo.Tuttavia, è possibile utilizzare un valore booleano, o flag, per consentire a un'iterazione del ciclo di indicare che la soluzione è stata trovata.Il runtime di concorrenza fornisce la funzionalità che consente a un'attività di annullare altre attività che non sono ancora state avviate.

Nell'esempio viene illustrato come convertire un ciclo parallelfor di OpenMP che non richiede l'esecuzione di tutte le iterazioni per utilizzare il meccanismo di annullamento del runtime di concorrenza.

Esempio

Nell'esempio vengono utilizzati sia OpenMP che il runtime di concorrenza per implementare una versione parallela dell'algoritmo std::any_of.La versione di OpenMP dell'esempio utilizza un flag per coordinare tra tutte le iterazioni del ciclo parallelo che la condizione è stata soddisfatta.La versione che utilizza il Runtime di concorrenza utilizza il concurrency::structured_task_group::cancel metodo per interrompere l'operazione complessiva quando la condizione è soddisfatta.

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

using namespace concurrency;
using namespace std;

// Uses OpenMP to determine whether a condition exists in 
// the specified range of elements.
template <class InIt, class Predicate>
bool omp_parallel_any_of(InIt first, InIt last, const Predicate& pr)
{
   typedef typename std::iterator_traits<InIt>::value_type item_type;

   // A flag that indicates that the condition exists.
   bool found = false;

   #pragma omp parallel for
      for (int i = 0; i < static_cast<int>(last-first); ++i)
      {
         if (!found)
         {
            item_type& cur = *(first + i);

            // If the element satisfies the condition, set the flag to 
            // cancel the operation.
            if (pr(cur)) {
               found = true;
            }
         }
      }

   return found;
}

// Uses the Concurrency Runtime to determine whether a condition exists in 
// the specified range of elements.
template <class InIt, class Predicate>
bool concrt_parallel_any_of(InIt first, InIt last, const Predicate& pr)
{
   typedef typename std::iterator_traits<InIt>::value_type item_type;

   structured_task_group tasks;

   // Create a predicate function that cancels the task group when
   // an element satisfies the condition.
   auto for_each_predicate = [&pr, &tasks](const item_type& cur) {
      if (pr(cur)) {
         tasks.cancel();
      }
   };

   // Create a task that calls the predicate function in parallel on each
   // element in the range.
   auto task = make_task([&]() {
       parallel_for_each(first, last, for_each_predicate);
   });

   // The condition is satisfied if the task group is in the cancelled state.
   return tasks.run_and_wait(task) == canceled;
}

int wmain()
{
   // The length of the array.
   const size_t size = 100000;

   // Create an array and initialize it with random values.
   array<int, size> a;   
   generate(begin(a), end(a), mt19937(42));

   // Search for a value in the array by using OpenMP and the Concurrency Runtime.

   const int what = 9114046;
   auto predicate = [what](int n) -> bool { 
      return (n == what);
   };

   wcout << L"Using OpenMP..." << endl;
   if (omp_parallel_any_of(begin(a), end(a), predicate))
   {
      wcout << what << L" is in the array." << endl;
   }
   else
   {
      wcout << what << L" is not in the array." << endl;
   }

   wcout << L"Using the Concurrency Runtime..." << endl;
   if (concrt_parallel_any_of(begin(a), end(a), predicate))
   {
      wcout << what << L" is in the array." << endl;
   }
   else
   {
      wcout << what << L" is not in the array." << endl;
   }
}

Questo esempio produce l'output che segue.

Using OpenMP...
9114046 is in the array.
Using the Concurrency Runtime...
9114046 is in the array.

Nella versione che utilizza OpenMP, tutte le iterazioni del ciclo vengono eseguite anche quando il flag è impostato.Inoltre, se un'attività contiene alcune attività figlio, il flag dovrà essere disponibile anche per tali attività figlio per comunicare l'annullamento.Nel runtime di concorrenza, quando un gruppo di attività viene annullato, il runtime annulla l'intero albero di lavoro, incluse le attività figlio.Il concurrency::parallel_for_each algoritmo utilizza le attività per eseguire le operazioni.Pertanto, quando un'iterazione del ciclo annulla l'attività radice, viene annullato anche l'intero albero di calcolo.Quando un albero di lavoro viene annullato, il runtime non avvia nuove attività.Tuttavia, il runtime consente il completamento delle attività che sono già state avviate.Pertanto, nel caso dell'algoritmo parallel_for_each le iterazioni del ciclo attive possono eseguire la pulizia delle risorse.

In entrambe le versioni dell'esempio, se la matrice contiene più di una copia del valore da cercare, più iterazioni del ciclo possono impostare contemporaneamente il risultato e annullare l'operazione globale.È possibile utilizzare una primitiva di sincronizzazione, ad esempio una sezione critica, se il problema richiede che solo un'attività esegua il lavoro quando viene soddisfatta una condizione.

È inoltre possibile utilizzare la gestione delle eccezioni per annullare le attività che utilizzano la libreria PPL.Per ulteriori informazioni sull'annullamento, vedere Annullamento nella libreria PPL.

Per ulteriori informazioni su parallel_for_each e altri algoritmi paralleli, vedere Algoritmi paralleli.

Compilazione del codice

Copiare il codice di esempio e incollarlo in un progetto di Visual Studio o incollarlo in un file denominato concrt-omp-parallelo-any-of.cpp e quindi eseguire il comando riportato di seguito in una finestra del prompt dei comandi di Visual Studio.

cl.exe /EHsc /openmp concrt-omp-parallel-any-of.cpp

Vedere anche

Concetti

Migrazione da OpenMP al runtime di concorrenza

Annullamento nella libreria PPL

Algoritmi paralleli