Compartilhar via


Como: Converter um Loop do OpenMP usa o cancelamento para usar o Runtime de simultaneidade

Alguns loops paralelos não exigem que todas as iterações seja executado. Por exemplo, um algoritmo que procura um valor pode terminar após o valor for encontrado. OpenMP não fornece um mecanismo para interromper um loop em paralelo. No entanto, você pode usar um valor booleano ou o sinalizador, para habilitar uma iteração do loop para indicar que a solução foi encontrada. O Runtime de simultaneidade fornece funcionalidade que permite que uma tarefa cancelar a outras tarefas que ainda não iniciaram.

Este exemplo demonstra como converter um OpenMP paralela para loop não requer para todas as iterações executar o usar o mecanismo de cancelamento de Runtime de simultaneidade.

Exemplo

Este exemplo usa o OpenMP e o Runtime de simultaneidade para implementar uma versão paralela a std::any_of algoritmo. A versão OpenMP Este exemplo usa um sinalizador para coordenar todas as iterações do loop paralelo que a condição foi atendida. A versão que usa o Runtime de simultaneidade usa a Concurrency::structured_task_group::cancel método para interromper a operação geral quando a condição for atendida.

// 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(a.begin(), a.end(), 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(a.begin(), a.end(), 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(a.begin(), a.end(), predicate))
   {
      wcout << what << L" is in the array." << endl;
   }
   else
   {
      wcout << what << L" is not in the array." << endl;
   }
}

O exemplo produz a seguinte saída.

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

Na versão do que utiliza OpenMP, execute todas as iterações do loop, mesmo quando o sinalizador é definido. Além disso, se uma tarefa tem tarefas filho, o sinalizador também teria que estar disponível para essas tarefas filho se comunique de cancelamento. O Runtime de simultaneidade, quando um grupo de tarefas for cancelado, o runtime cancela toda a árvore de trabalho, incluindo tarefas filho. O Concurrency::parallel_for_each usa o algoritmo de tarefas para realizar o trabalho. Portanto, quando uma iteração do loop cancela a tarefa de raiz, toda a árvore de computação também é cancelada. Quando uma árvore de trabalho for cancelada, o runtime não inicia novas tarefas. Entretanto, o tempo de execução permite tarefas que já tenham sido iniciadas para concluir. Portanto, no caso do parallel_for_each , algoritmo de iterações do loop ativo podem limpar seus recursos.

As duas versões desse exemplo, se a matriz contém mais de uma cópia do valor a ser pesquisado, várias iterações do loop podem cada conjunto, simultaneamente, o resultado e cancelar a operação geral. Você pode usar um primitivo de sincronização como, por exemplo, uma seção crítica, se o seu problema requer que apenas uma tarefa executa o trabalho quando uma condição for atendida.

Você também pode usar o tratamento de exceção para cancelar as tarefas que usam a PPL. Para obter mais informações sobre o cancelamento, consulte Cancelamento na PPL.

Para obter mais informações sobre parallel_for_each e outros algoritmos paralelos, consulte Algoritmos paralelos.

Compilando o código

Copie o código de exemplo e colá-lo em um Visual Studio do projeto, ou colá-lo em um arquivo que é chamado concrt-omp-paralelo-any-of.cpp e, em seguida, execute o seguinte comando um Visual Studio 2010 janela do Prompt de comando.

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

Consulte também

Conceitos

Cancelamento na PPL

Algoritmos paralelos

Outros recursos

Migrando do OpenMP para o Runtime de simultaneidade