Gör så här: Konvertera en OpenMP-loop som använder Annullering för att använda Samtidighetskörning

Vissa parallella loopar kräver inte att alla iterationer körs. Till exempel kan en algoritm som söker efter ett värde avslutas när värdet har hittats. OpenMP tillhandahåller ingen mekanism för att bryta sig ur en parallell loop. Du kan dock använda ett booleskt värde eller en flagga för att aktivera en iteration av loopen för att indikera att lösningen har hittats. Concurrency Runtime innehåller funktioner som gör att en aktivitet kan avbryta andra aktiviteter som ännu inte har startats.

Det här exemplet visar hur du konverterar en OpenMP parallelför-loop som inte kräver att alla iterationer körs till att använda Concurrency Runtimes avbrytningsmekanism.

Exempel

I det här exemplet används både OpenMP och Concurrency Runtime för att implementera en parallell version av std::any_of-algoritmen . OpenMP-versionen av det här exemplet använder en flagga för att samordna alla parallella iterationer av loopen när villkoret har uppfyllts. Den version som använder Concurrency Runtime använder metoden concurrency::structured_task_group::cancel för att stoppa den övergripande åtgärden när villkoret uppfylls.

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

Det här exemplet genererar följande utdata.

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

I den version av som använder OpenMP körs alla iterationer av loopen, även när flaggan har angetts. Om en uppgift dessutom skulle ha några underordnade uppgifter måste flaggan också vara tillgänglig för dessa underordnade uppgifter för att kommunicera annullering. När en uppgiftsgrupp avbryts i "Concurrency Runtime" avbryter systemet hela trädet av arbete, inklusive underordnade uppgifter. concurrency::parallel_for_each-algoritmen använder uppgifter för att utföra arbete. När en iteration av loopen avbryter rotuppgiften avbryts därför även hela beräkningsträdet. När ett arbetsträd avbryts startar inte körningstiden nya uppgifter. Körmiljön tillåter dock att uppgifter som redan har startat slutförs. När det gäller algoritmen parallel_for_each kan därför aktiva loop-iterationer rensa sina resurser.

I båda versionerna av det här exemplet, om matrisen innehåller mer än en kopia av värdet att söka efter, kan flera loop-iterationer samtidigt ange resultatet och avbryta den övergripande åtgärden. Du kan använda en synkroniseringsprimativ, till exempel ett kritiskt avsnitt, om problemet kräver att endast en uppgift utför arbete när ett villkor uppfylls.

Du kan också använda undantagshantering för att avbryta uppgifter som använder PPL. Mer information om annullering finns i Annullering i PPL.

Mer information om parallel_for_each och andra parallella algoritmer finns i Parallella algoritmer.

Kompilera koden

Kopiera exempelkoden och klistra in den i ett Visual Studio-projekt, eller klistra in den i en fil med namnet concrt-omp-parallel-any-of.cpp och kör sedan följande kommando i ett Visual Studio-kommandotolkfönster.

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

Se även

Migrera från OpenMP till Concurrency Runtime
Annullering i PPL
Parallella algoritmer