Sdílet prostřednictvím


Postupy: Převedení smyčky OpenMP využívající zrušení na využití modulu Concurrency Runtime

Některé paralelní smyčky nevyžadují spuštění všech iterací. Například algoritmus, který vyhledá hodnotu, se může ukončit po nalezení hodnoty. OpenMP neposkytuje mechanismus pro přerušení paralelní smyčky. Pokud ale chcete povolit iteraci smyčky, můžete použít logickou hodnotu nebo příznak, která indikuje, že řešení bylo nalezeno. Concurrency Runtime poskytuje funkce, které umožňují jedné úloze zrušit jiné úlohy, které ještě nebyly spuštěny.

Tento příklad ukazuje, jak převést paralelněOpenMP pro smyčku, která nevyžaduje spuštění všech iterací pro použití mechanismu zrušení Concurrency Runtime.

Příklad

Tento příklad používá OpenMP i Concurrency Runtime k implementaci paralelní verze algoritmu std::any_of . Verze OpenMP tohoto příkladu používá příznak ke koordinaci mezi všemi iteracemi paralelní smyčky, které byla splněna podmínka. Verze, která používá Concurrency Runtime, používá souběžnost::structured_task_group::cancel metoda k zastavení celkové operace při splnění podmínky.

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

Tento příklad vytvoří následující výstup.

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

Ve verzi, která používá OpenMP, se spustí všechny iterace smyčky, i když je příznak nastaven. Navíc pokud by úkol měl mít nějaké podřízené úkoly, musí být příznak také k dispozici těmto podřízeným úkolům ke komunikaci zrušení. Při zrušení skupiny úloh v modulu Concurrency Runtime modul runtime zruší celý strom práce, včetně podřízených úkolů. Souběžnost ::p arallel_for_each algoritmus používá úlohy k provádění práce. Proto když jedna iterace smyčky zruší kořenovou úlohu, celý strom výpočtu se také zruší. Když dojde ke zrušení stromu práce, modul runtime nespustí nové úlohy. Modul runtime však umožňuje úkoly, které už byly zahájeny, aby se dokončily. Proto v případě parallel_for_each algoritmu mohou aktivní iterace smyčky vyčistit své prostředky.

V obou verzích tohoto příkladu, pokud pole obsahuje více než jednu kopii hodnoty, kterou chcete vyhledat, může několik iterací smyček současně nastavit výsledek a zrušit celkovou operaci. Pokud váš problém vyžaduje, aby při splnění podmínky fungoval pouze jeden úkol, můžete použít primitivní synchronizaci, například kritickou část.

Zpracování výjimek můžete použít také ke zrušení úloh, které používají PPL. Další informace o zrušení naleznete v tématu Zrušení v PPL.

Další informace o parallel_for_each paralelních algoritmech a dalších paralelních algoritmech najdete v tématu Paralelní algoritmy.

Probíhá kompilace kódu

Zkopírujte ukázkový kód a vložte ho do projektu sady Visual Studio nebo ho vložte do pojmenovaného concrt-omp-parallel-any-of.cpp souboru a potom v okně příkazového řádku sady Visual Studio spusťte následující příkaz.

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

Viz také

Migrace z OpenMP do Concurrency Runtime
Zrušení v knihovně PPL
Paralelní algoritmy