Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Alcuni cicli paralleli non richiedono l'esecuzione di tutte le iterazioni. Ad esempio, un algoritmo che cerca un valore può terminare dopo la ricerca del valore. OpenMP non fornisce un meccanismo per interrompere un ciclo parallelo. Tuttavia, è possibile usare un valore booleano o un flag per abilitare un'iterazione del ciclo per indicare che la soluzione è stata trovata. Il runtime di concorrenza fornisce funzionalità che consentono a un'attività di annullare altre attività che non sono ancora state avviate.
In questo esempio viene illustrato come convertire un ciclo OpenMP parallelofor che non richiede l'esecuzione di tutte le iterazioni per l'uso del meccanismo di annullamento del runtime di concorrenza.
Esempio
Questo esempio usa sia OpenMP che Il runtime di concorrenza per implementare una versione parallela dell'algoritmo std::any_of . La versione OpenMP di questo esempio usa un flag per coordinare tutte le iterazioni del ciclo parallelo soddisfatte dalla condizione. La versione che usa il runtime di concorrenza usa il metodo concurrency::structured_task_group::cancel per arrestare l'operazione complessiva quando viene soddisfatta la condizione.
// 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;
}
}
Questo esempio produce il seguente output:
Using OpenMP...
9114046 is in the array.
Using the Concurrency Runtime...
9114046 is in the array.
Nella versione di che usa OpenMP, tutte le iterazioni del ciclo vengono eseguite, anche quando il flag è impostato. Inoltre, se un'attività dovesse avere attività figlio, il flag dovrà anche essere disponibile per tali attività figlio per comunicare l'annullamento. Nel runtime di concorrenza, quando un gruppo di attività viene annullato, il runtime annulla l'intero albero del lavoro, incluse le attività figlio. L'algoritmo concurrency::p arallel_for_each usa le attività per eseguire il lavoro. Pertanto, quando un'iterazione del ciclo annulla l'attività radice, viene annullata anche l'intera struttura ad albero di calcolo. Quando un albero del lavoro viene annullato, il runtime non avvia nuove attività. Tuttavia, il runtime consente attività che hanno già iniziato a terminare. Pertanto, nel caso dell'algoritmo parallel_for_each , le iterazioni del ciclo attivo possono pulire le risorse.
In entrambe le versioni di questo esempio, se la matrice contiene più copie del valore da cercare, più iterazioni del ciclo possono impostare contemporaneamente il risultato e annullare l'operazione complessiva. È possibile usare una primitiva di sincronizzazione, ad esempio una sezione critica, se il problema richiede che venga eseguita una sola attività quando viene soddisfatta una condizione.
È anche possibile usare la gestione delle eccezioni per annullare le attività che usano la libreria PPL. Per altre informazioni sull'annullamento, vedere Annullamento in PPL.
Per altre informazioni su parallel_for_each e altri algoritmi paralleli, vedere Algoritmi paralleli.
Compilazione del codice
Copiare il codice di esempio e incollarlo in un progetto di Visual Studio oppure incollarlo in un file denominato concrt-omp-parallel-any-of.cpp e quindi eseguire il comando seguente in una finestra del prompt dei comandi di Visual Studio.
cl.exe /EHsc /openmp concrt-omp-parallel-any-of.cpp
Vedi anche
Migrazione da OpenMP al runtime di concorrenza
Annullamento nella libreria PPL
Algoritmi paralleli