Compartilhar via


Como: Converter um loop de OpenMP que usa o botão para usar o tempo de execução de concorrência

Alguns loop paralelos não exigem que todos os iterações foram executadas.Por exemplo, um algoritmo que procura por um valor pode finalizar depois que o valor for encontrado.OpenMP não fornece um mecanismo para quebrar de um loop paralelo.No entanto, você pode usar um valor Booleano, ou o sinalizador, para ativar uma iteração do loop para indicar que a solução esteve encontrada.O tempo de execução de simultaneidade fornece funcionalidade que permite uma tarefa cancelar outras tarefas que ainda não seguir o iniciarão.

Este exemplo mostra como converter um loop de OpenMP paralelapara que não requer que todas as iterações executem para usar o mecanismo de cancelamento de tempo de execução de simultaneidade.

Exemplo

Este exemplo usa OpenMP e o tempo de execução de simultaneidade para implementar uma versão paralela do algoritmo de std::any_of .A versão de OpenMP este exemplo usa um sinalizador para coordenar entre todas as iterações paralelas do loop que a condição esteve satisfeita.A versão que usa o tempo de execução de simultaneidade usa o método de concurrency::structured_task_group::cancel para interromper a operação total quando a condição seja satisfeita.

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

O exemplo produz a seguinte saída.

  
  
  
  

Na versão do que usa OpenMP, todas as iterações do loop executam, mesmo quando o sinalizador é definido.Além disso, se uma tarefa não ter quaisquer tarefas filhos, o parâmetro também precisará estar disponível 2 essas tarefas filhos comunicar cancelamento.Em tempo de execução de concorrência, quando um grupo de trabalho é cancelado, o tempo de execução cancela a árvore inteira de trabalho, incluindo tarefas filhos.As tarefas dos usos do algoritmo de concurrency::parallel_for_each realizar trabalho.Como consequência, 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 é cancelado, o tempo de execução não começa novas tarefas.No entanto, o tempo de execução permite as tarefas que já têm introdução para concluir.Como consequência, no caso do algoritmo de parallel_for_each , as iterações ativos do loop podem limpar os recursos.

Em ambas as versões deste exemplo, se a matriz contém mais de uma cópia do valor para procurar por, várias iterações do loop podem acessar cada definem simultaneamente o resultado e cancelarem a operação total.Você pode usar uma primitiva de sincronização, como uma seção crítica, se seu problema que requer apenas uma tarefa o trabalho é executado quando uma condição seja satisfeita.

Você também pode usar tratamento de exceções para cancelar as tarefas que usam o PPL.Para obter mais informações sobre o botão, consulte Cancelar o 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 cole-o em um projeto do Visual Studio, ou cole em um arquivo denominado concrt-omp-parallel-any-of.cpp e execute o seguinte comando em uma janela de prompt de comando do Visual Studio.

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

Consulte também

Conceitos

Migrando de OpenMP ao tempo de execução de concorrência

Cancelar o PPL

Algoritmos paralelos