방법: 동시성 런타임을 사용하기 위해 취소를 사용하는 OpenMP 루프 변환
일부 병렬 루프는 모든 반복을 실행할 필요가 없습니다. 예를 들어 값을 검색하는 알고리즘은 값을 찾은 후 종료할 수 있습니다. OpenMP는 병렬 루프를 중단하는 메커니즘을 제공하지 않습니다. 그러나 부울 값 또는 플래그를 사용하여 루프를 반복하여 솔루션이 발견되었음을 나타낼 수 있습니다. 동시성 런타임은 한 작업이 아직 시작되지 않은 다른 작업을 취소할 수 있도록 하는 기능을 제공합니다.
이 예제에서는 동시성 런타임 취소 메커니즘을 사용하기 위해 모든 반복을 실행할 필요가 없는 루프용 OpenMP 병렬을 변환하는 방법을 보여 줍니다.
예시
이 예제에서는 OpenMP와 동시성 런타임을 모두 사용하여 std::any_of 알고리즘의 병렬 버전을 구현합니다. 이 예제의 OpenMP 버전은 플래그를 사용하여 조건이 충족된 모든 병렬 루프 반복을 조정합니다. 동시성 런타임을 사용하는 버전은 조건이 충족될 때 동시성::structured_task_group::cancel 메서드를 사용하여 전체 작업을 중지합니다.
// 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;
}
}
이 예제의 결과는 다음과 같습니다.
Using OpenMP...
9114046 is in the array.
Using the Concurrency Runtime...
9114046 is in the array.
OpenMP를 사용하는 버전에서는 플래그가 설정된 경우에도 루프의 모든 반복이 실행됩니다. 또한 작업에 자식 작업이 있는 경우 취소를 전달하려면 해당 자식 작업에서도 플래그를 사용할 수 있어야 합니다. 동시성 런타임에서 작업 그룹이 취소되면 런타임은 자식 작업을 포함하여 전체 작업 트리를 취소합니다. concurrency::p arallel_for_each 알고리즘은 작업을 사용하여 작업을 수행합니다. 따라서 루프를 한 번 반복하면 루트 작업이 취소되면 전체 계산 트리도 취소됩니다. 작업 트리가 취소되면 런타임은 새 작업을 시작하지 않습니다. 그러나 런타임을 사용하면 이미 시작된 작업이 완료될 수 있습니다. 따라서 알고리즘의 parallel_for_each
경우 활성 루프 반복이 리소스를 클린 수 있습니다.
이 예제의 두 버전에서 배열에 검색할 값의 복사본이 두 개 이상 포함된 경우 여러 루프 반복이 동시에 결과를 설정하고 전체 작업을 취소할 수 있습니다. 조건이 충족되는 경우 하나의 작업만 작업을 수행해야 하는 경우 중요한 섹션과 같은 동기화 기본 형식을 사용할 수 있습니다.
예외 처리를 사용하여 PPL을 사용하는 작업을 취소할 수도 있습니다. 취소에 대한 자세한 내용은 PPL의 취소를 참조하세요.
병렬 알고리즘 및 기타 병렬 알고리즘에 대한 parallel_for_each
자세한 내용은 병렬 알고리즘을 참조 하세요.
코드 컴파일
예제 코드를 복사하여 Visual Studio 프로젝트에 붙여넣거나 이름이 지정된 concrt-omp-parallel-any-of.cpp
파일에 붙여넣은 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행합니다.
cl.exe /EHsc /openmp concrt-omp-parallel-any-of.cpp