Megosztás a következőn keresztül:


Útmutató: A megszakítást használó OpenMP-ciklus átalakítása az egyidejűségi futtatókörnyezet használatára

Egyes párhuzamos hurkok nem igénylik az összes iteráció végrehajtását. Egy értéket kereső algoritmus például az érték megtalálása után leállhat. Az OpenMP nem biztosít mechanizmust a párhuzamos hurkokból való kibontáshoz. Logikai érték vagy jelölő használatával azonban engedélyezheti a hurok egy iterációját annak jelzésére, hogy a megoldás megtalálása megtörtént. Az egyidejűségi futtatókörnyezet olyan funkciókat biztosít, amelyek lehetővé teszik, hogy egy tevékenység megszakítsa a még el nem indított egyéb tevékenységeket.

Ez a példa bemutatja, hogyan alakíthat át egy OpenMP párhuzamosfor ciklust olyan formára, amely nem igényli az összes iteráció futtatását, az Egyszerre Futtatás futásidejű lemondási mechanizmusának használatához.

példa

Ez a példa az OpenMP-t és az egyidejűségi futtatókörnyezetet is használja az std::any_of algoritmus párhuzamos verziójának implementálásához. A példa OpenMP-verziója egy jelölő használatával koordinálja a feltétel teljesülését jelző összes párhuzamos ciklus iterációja között. Az egyidejűségi futtatókörnyezetet használó verzió az egyidejűség::structured_task_group::cancel metódust használja a teljes művelet leállításához, amikor a feltétel teljesül.

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

Ez a példa a következő kimenetet hozza létre.

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

Az OpenMP-t használó verzióban a ciklus összes iterációja végrehajtódik, még akkor is, ha a zászló be van állítva. Továbbá, ha egy feladat gyermekfeladatokkal rendelkezne, a jelzőnek a lemondás közléséhez is rendelkezésre kell állnia a gyermekfeladatok számára. Az egyidejűségi futtatókörnyezetben egy tevékenységcsoport megszakítása esetén a futtatókörnyezet megszakítja a teljes munkafát, beleértve a gyermekfeladatokat is. Az concurrency::parallel_for_each algoritmus a feladatok segítségével végzi el a munkát. Ezért amikor a ciklus egyik iterációja megszakítja a gyökérfeladatot, a teljes számítási fa is megszakad. Ha a munkafát megszakítják, a futtatókörnyezet nem indít el új feladatokat. A futtatókörnyezet azonban lehetővé teszi a már megkezdett tevékenységek befejezését. Ezért az algoritmus esetében az parallel_for_each aktív ciklus iterációi megtisztíthatják az erőforrásaikat.

A példa mindkét verziójában, ha a tömb a keresendő érték egynél több példányát tartalmazza, egyszerre több ciklusos iteráció is beállíthatja az eredményt, és megszakíthatja a teljes műveletet. Használhat egy szinkronizálási primitívet, például egy kritikus szakaszt, ha a probléma megköveteli, hogy egy feltétel teljesülése esetén csak egy tevékenység működjön.

A PPL-t használó tevékenységek megszakításához kivételkezelést is használhat. További információ a lemondásról: Lemondás a PPL-ben.

További információ a parallel_for_each párhuzamos algoritmusokról és más párhuzamos algoritmusokról: Párhuzamos algoritmusok.

A kód összeállítása

Másolja ki a példakódot, és illessze be egy Visual Studio-projektbe, vagy illessze be egy elnevezett concrt-omp-parallel-any-of.cpp fájlba, majd futtassa a következő parancsot egy Visual Studio parancssori ablakban.

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

Lásd még

Migrálás az OpenMP-ről az egyidejűségi futtatókörnyezetbe
Lemondás a PPL-ben
Párhuzamos algoritmusok