Aracılığıyla paylaş


Nasıl yapılır: Eşzamanlılık Çalışma Zamanı Kullanmak için İptali Kullanan bir OpenMP Döngüsünü Dönüştürme

Bazı paralel döngüler tüm yinelemelerin yürütülmesini gerektirmez. Örneğin, bir değeri arayan bir algoritma, değer bulunduktan sonra sonlandırılabilir. OpenMP, paralel döngüden çıkmak için bir mekanizma sağlamaz. Ancak, çözümün bulunduğunu belirtmek üzere döngünün yinelenmesini etkinleştirmek için Boole değeri veya bayrağı kullanabilirsiniz. Eşzamanlılık Çalışma Zamanı, bir görevin henüz başlatılmamış diğer görevleri iptal etmelerini sağlayan işlevler sağlar.

Bu örnekte, Eşzamanlılık Çalışma Zamanı iptal mekanizmasını kullanmak üzere tüm yinelemelerin çalıştırılmasını gerektirmeyen bir Döngü için OpenMP paralelininnasıl dönüştürüldüğü gösterilmektedir.

Örnek

Bu örnekte std::any_of algoritmasının paralel bir sürümünü uygulamak için hem OpenMP hem de Eşzamanlılık Çalışma Zamanı kullanılır. Bu örneğin OpenMP sürümü, koşulun karşılandığı tüm paralel döngü yinelemeleri arasında koordinasyon sağlamak için bir bayrak kullanır. Eşzamanlılık Çalışma Zamanı'nı kullanan sürüm, koşul karşılandığında genel işlemi durdurmak için eşzamanlılık::structured_task_group::cancel yöntemini kullanır.

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

Bu örnek aşağıdaki çıkışı oluşturur.

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

OpenMP kullanan sürümünde, bayrağı ayarlandığında bile döngünün tüm yinelemeleri yürütülür. Ayrıca, bir görevin alt görevleri varsa, iptali iletmek için bayrağın bu alt görevlerin de kullanılabilir olması gerekir. Eşzamanlılık Çalışma Zamanı'nda, bir görev grubu iptal edildiğinde çalışma zamanı alt görevler de dahil olmak üzere iş ağacının tamamını iptal eder. Concurrency::p arallel_for_each algoritması, iş gerçekleştirmek için görevleri kullanır. Bu nedenle, döngünün bir yinelemesi kök görevi iptal ettiğinde, hesaplama ağacının tamamı da iptal edilir. Bir iş ağacı iptal edildiğinde, çalışma zamanı yeni görevleri başlatmaz. Ancak çalışma zamanı, zaten başlamış olan görevlerin bitmesini sağlar. Bu nedenle, algoritma söz konusu olduğunda parallel_for_each etkin döngü yinelemeleri kaynaklarını temizleyebilir.

Bu örneğin her iki sürümünde de dizi aranacak değerin birden fazla kopyasını içeriyorsa, her biri aynı anda sonucu ayarlayıp genel işlemi iptal edebilir. Sorununuz bir koşul karşılandığında yalnızca bir görevin iş gerçekleştirmesini gerektiriyorsa, kritik bölüm gibi bir eşitleme temel öğesini kullanabilirsiniz.

PPL kullanan görevleri iptal etmek için özel durum işlemeyi de kullanabilirsiniz. İptal hakkında daha fazla bilgi için bkz . PPL'de İptal.

ve diğer paralel algoritmalar hakkında parallel_for_each daha fazla bilgi için bkz . Paralel Algoritmalar.

Kod Derleniyor

Örnek kodu kopyalayıp bir Visual Studio projesine yapıştırın veya adlı concrt-omp-parallel-any-of.cpp bir dosyaya yapıştırın ve ardından bir Visual Studio Komut İstemi penceresinde aşağıdaki komutu çalıştırın.

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

Ayrıca bkz.

OpenMP döngüsünden Eşzamanlılık Çalışma Zamanına geçiş
PPL'de İptal
Paralel Algoritmalar