Udostępnij za pośrednictwem


Porady: konwertowanie pętli OpenMP stosującej anulowanie do korzystania ze współbieżności środowiska wykonawczego

Niektóre pętle równoległe nie wymagają wykonania wszystkich iteracji. Na przykład algorytm, który wyszukuje wartość, może zakończyć się po znalezieniu wartości. Protokół OpenMP nie zapewnia mechanizmu podziału pętli równoległej. Można jednak użyć wartości logicznej lub flagi, aby umożliwić iterację pętli, aby wskazać, że rozwiązanie zostało znalezione. Środowisko uruchomieniowe współbieżności udostępnia funkcje, które umożliwiają jednemu zadaniu anulowanie innych zadań, które nie zostały jeszcze uruchomione.

W tym przykładzie pokazano, jak przekonwertować równoległąpętlę OpenMP, która nie wymaga uruchomienia wszystkich iteracji w celu użycia mechanizmu anulowania środowiska uruchomieniowego współbieżności.

Przykład

W tym przykładzie użyto zarówno protokołu OpenMP, jak i środowiska uruchomieniowego współbieżności, aby zaimplementować równoległą wersję algorytmu std::any_of . Wersja openMP tego przykładu używa flagi do koordynowania wszystkich iteracji pętli równoległej, które zostały spełnione. Wersja używająca środowiska uruchomieniowego współbieżności używa metody concurrency::structured_task_group::cancel , aby zatrzymać ogólną operację po spełnieniu warunku.

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

W tym przykładzie są generowane następujące dane wyjściowe.

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

W wersji programu , która używa protokołu OpenMP, wszystkie iteracji pętli są wykonywane nawet wtedy, gdy flaga jest ustawiona. Ponadto, jeśli zadanie miało mieć jakiekolwiek zadania podrzędne, flaga musiałaby być również dostępna dla tych zadań podrzędnych w celu komunikowania się z anulowaniem. W środowisku uruchomieniowym współbieżności po anulowaniu grupy zadań środowisko uruchomieniowe anuluje całe drzewo pracy, w tym zadania podrzędne. Współbieżność ::p arallel_for_each algorytm używa zadań do wykonywania pracy. W związku z tym, gdy jedna iteracja pętli anuluje zadanie główne, całe drzewo obliczeń również zostanie anulowane. Po anulowaniu drzewa pracy środowisko uruchomieniowe nie uruchamia nowych zadań. Jednak środowisko uruchomieniowe umożliwia wykonywanie zadań, które zostały już uruchomione. W związku z tym w przypadku algorytmu parallel_for_each iteracje aktywnej pętli mogą czyścić swoje zasoby.

W obu wersjach tego przykładu, jeśli tablica zawiera więcej niż jedną kopię wartości do wyszukania, iteracje wielu pętli mogą jednocześnie ustawić wynik i anulować ogólną operację. Można użyć elementu pierwotnego synchronizacji, takiego jak sekcja krytyczna, jeśli problem wymaga, aby tylko jedno zadanie wykonało pracę po spełnieniu warunku.

Można również użyć obsługi wyjątków, aby anulować zadania korzystające z PPL. Aby uzyskać więcej informacji na temat anulowania, zobacz Anulowanie w PPL.

Aby uzyskać więcej informacji na temat parallel_for_each i innych algorytmów równoległych, zobacz Parallel Algorithms (Algorytmy równoległe).

Kompilowanie kodu

Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wklej go w pliku o nazwie concrt-omp-parallel-any-of.cpp , a następnie uruchom następujące polecenie w oknie wiersza polecenia programu Visual Studio.

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

Zobacz też

Migrowanie z OpenMP do środowiska uruchomieniowego współbieżności
Anulowanie w PPL
Algorytmy równoległe