Delen via


Procedure: Een OpenMP-lus converteren die gebruikmaakt van annulering om de gelijktijdigheidsruntime te gebruiken

Voor sommige parallelle lussen is niet vereist dat alle iteraties worden uitgevoerd. Een algoritme dat naar een waarde zoekt, kan bijvoorbeeld worden beëindigd nadat de waarde is gevonden. OpenMP biedt geen mechanisme om een parallelle lus uit te breken. U kunt echter een Booleaanse waarde of vlag gebruiken om een iteratie van de lus in te schakelen om aan te geven dat de oplossing is gevonden. De Gelijktijdigheidsruntime biedt functionaliteit waarmee een taak andere taken kan annuleren die nog niet zijn gestart.

In dit voorbeeld ziet u hoe u een OpenMP-parallelconverteert voor een lus die niet vereist dat alle iteraties worden uitgevoerd om het annuleringsmechanisme van Concurrency Runtime te gebruiken.

Voorbeeld

In dit voorbeeld worden zowel OpenMP als de Gelijktijdigheidsruntime gebruikt om een parallelle versie van het std::any_of-algoritme te implementeren. De OpenMP-versie van dit voorbeeld gebruikt een vlag om te coördineren onder alle parallelle lusiteraties wanneer aan de voorwaarde is voldaan. De versie die gebruikmaakt van de Concurrency Runtime past de methode concurrency::structured_task_group::cancel toe om de gehele bewerking te stoppen wanneer aan de voorwaarde wordt voldaan.

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

In dit voorbeeld wordt de volgende uitvoer geproduceerd.

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

In de versie van die gebruikmaakt van OpenMP worden alle iteraties van de lus uitgevoerd, zelfs wanneer de vlag is ingesteld. Als een taak onderliggende taken zou hebben, zou de vlag ook beschikbaar moeten zijn voor die onderliggende taken om annulering te communiceren. Wanneer een taakgroep wordt geannuleerd in de Gelijktijdigheidsruntime, annuleert de runtime de volledige structuur van het werk, inclusief onderliggende taken. Het concurrentie::parallel_for_each algoritme gebruikt taken om werk uit te voeren. Wanneer een iteratie van de lus de hoofdtaak annuleert, wordt de hele structuur van de berekening ook geannuleerd. Wanneer een werkstructuur wordt geannuleerd, start de runtime geen nieuwe taken. De runtime staat echter taken toe die al zijn begonnen met voltooien. Daarom kunnen actieve lusiteraties, bij gebruik van het parallel_for_each algoritme, hun resources opschonen.

Als in beide versies van dit voorbeeld de matrix meer dan één kopie van de te zoeken waarde bevat, kunnen meerdere lusiteraties elk tegelijk het resultaat instellen en de algehele bewerking annuleren. U kunt een synchronisatieprimitief, zoals een kritieke sectie, gebruiken als uw probleem vereist dat slechts één taak werkt wanneer aan een voorwaarde wordt voldaan.

U kunt ook uitzonderingsafhandeling gebruiken om taken te annuleren die gebruikmaken van de PPL. Zie Annulering in de PPL voor meer informatie over annulering.

Zie parallel_for_each algoritmen voor meer informatie over en andere parallelle algoritmen.

De code compileren

Kopieer de voorbeeldcode en plak deze in een Visual Studio-project, of plak deze in een bestand met de naam concrt-omp-parallel-any-of.cpp en voer vervolgens de volgende opdracht uit in een Visual Studio-opdrachtpromptvenster.

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

Zie ook

Migreren van OpenMP naar de Gelijktijdigheidsruntime
Annulering in de PPL
Parallelle algoritmen