방법: 동시성 런타임을 사용하기 위해 취소를 사용하는 OpenMP 루프 변환

일부 병렬 루프의 경우에는 모든 반복을 실행할 필요가 없습니다.예를 들어 값을 검색하는 알고리즘은 값을 찾은 후에 종료될 수 있습니다.OpenMP에서는 병렬 루프를 벗어나는 메커니즘을 제공하지 않습니다.그러나 부울 값 또는 플래그를 사용하여 루프 반복이 솔루션을 찾았음을 나타내도록 할 수 있습니다.동시성 런타임에서는 하나의 작업이 아직 시작되지 않은 다른 작업을 취소할 수 있게 하는 기능을 제공합니다.

이 예제에서는 동시성 런타임 취소 메커니즘을 사용하기 위해 모든 반복을 실행해야 할 필요는 없는 OpenMP parallelfor 루프를 변환하는 방법을 보여 줍니다.

예제

이 예제에서는 OpenMP 및 동시성 런타임을 사용하여 병렬 버전의 std::any_of 알고리즘을 구현합니다.이 예제의 OpenMP 버전에서는 플래그를 사용하여 조건이 충족된 모든 병렬 루프 반복 간에 조정합니다.동시성 런타임을 사용 하는 버전을 사용 하 여 concurrency::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::parallel_for_each 알고리즘 작업을 사용 하 여 작업을 수행 합니다.따라서 루프의 한 반복에서 루트 작업을 취소하면 전체 계산 트리도 취소됩니다.작업(work) 트리를 취소하면 런타임에서 새 작업(task)을 시작하지 않습니다.그러나 런타임에서는 이미 시작된 작업이 끝나도록 허용합니다.따라서 parallel_for_each 알고리즘의 경우 활성 루프 반복이 해당 리소스를 정리할 수 있습니다.

이 예제의 두 버전에서 배열에 검색할 값의 복사본이 두 개 이상 있으면 여러 루프 반복에서 각각 동시에 결과를 설정하고 전체 작업을 취소할 수 있습니다.조건이 충족될 때 하나의 작업만 수행되어야 하는 경우 임계 영역과 같은 동기화 기본 형식을 사용할 수 있습니다.

PPL을 사용하는 작업을 취소하는 데 예외 처리를 사용할 수도 있습니다.취소에 대한 자세한 내용은 PPL에서의 취소를 참조하십시오.

parallel_for_each 및 기타 병렬 알고리즘에 대한 자세한 내용은 병렬 알고리즘을 참조하십시오.

코드 컴파일

예제 코드를 복사 하 고 Visual Studio 프로젝트에 붙여 또는 라는 파일에 붙여 concrt-omp-병렬-모든-of.cpp 및 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행 합니다.

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

참고 항목

개념

OpenMP에서 동시성 런타임으로 마이그레이션

PPL에서의 취소

병렬 알고리즘