如何:转换 OpenMP parallel for 循环以使用并发运行时

本示例演示如何转换使用 OpenMP parallelfor 指令的基本循环,以便使用并发运行时 Concurrency::parallel_for 算法。

示例

本示例使用 OpenMP 和并发运行时计算随机值数组中质数的计数。

// concrt-omp-count-primes.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <random>
#include <array>
#include <iostream>

using namespace Concurrency;
using namespace std;

// Determines whether the input value is prime.
bool is_prime(int n)
{
   if (n < 2)
      return false;
   for (int i = 2; i < n; ++i)
   {
      if ((n % i) == 0)
         return false;
   }
   return true;
}

// Uses OpenMP to compute the count of prime numbers in an array.
void omp_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   size_t count = 0;
   #pragma omp parallel for
      for (int i = 0; i < static_cast<int>(size); ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an array.
void concrt_count_primes(int* a, size_t size)
{
   if (size == 0)
      return;

   combinable<size_t> counts;
   parallel_for<size_t>(0, size, [&](size_t i) 
   {
      if (is_prime(a[i])) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

int wmain()
{
   // The length of the array.
   const size_t size = 1000000;

   // Create an array and initialize it with random values.
   int* a = new int[size];

   mt19937 gen(42);
   for (size_t i = 0; i < size; ++i) {
      a[i] = gen();
   }

   // Count prime numbers by using OpenMP and the Concurrency Runtime.

   wcout << L"Using OpenMP..." << endl;
   omp_count_primes(a, size);

   wcout << L"Using the Concurrency Runtime..." << endl;
   concrt_count_primes(a, size);

   delete[] a;
}

该示例产生下面的输出。

Using OpenMP...
found 107254 prime numbers.
Using the Concurrency Runtime...
found 107254 prime numbers.

parallel_for 算法和 OpenMP 3.0 允许索引类型成为带符号的整数类型或不带符号的整数类型。 parallel_for 算法还确保指定范围不会溢出带符号类型。 OpenMP 2.0 和 2.5 版只允许带符号的整数索引类型。 OpenMP 也不验证索引范围。

使用并发运行时的此示例版本还使用 atomic 指令中的 Concurrency::combinable 对象在无需同步的情况下递增计数器值。

有关 parallel_for 和其他并行算法的更多信息,请参见并行算法。 有关 combinable 类的更多信息,请参见并行容器和对象

此示例修改了前面的示例,以便作用于 std::array 对象而不是本机数组。 因为 OpenMP 2.0 和 2.5 版只在 parallel for 构造中允许带符号的整数索引类型,所以您无法使用迭代器并行访问标准模板库 (STL) 容器中的元素。 并行模式库 (PPL) 提供 Concurrency::parallel_for_each 算法,以便在迭代容器上并行执行任务(如 STL 提供的任务)。 此算法使用的分区逻辑与 parallel_for 算法使用的分区逻辑相同。 parallel_for_each 算法与 STL std::for_each 算法类似,只是 parallel_for_each 算法并发执行任务。

// Uses OpenMP to compute the count of prime numbers in an 
// array object.
template<size_t Size>
void omp_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   size_t count = 0;
   int size = static_cast<int>(a.size());
   #pragma omp parallel for
      for (int i = 0; i < size; ++i)
      {
         if (is_prime(a[i])) {
            #pragma omp atomic
               ++count;
         }
      }

   wcout << L"found " << count 
         << L" prime numbers." << endl;
}

// Uses the Concurrency Runtime to compute the count of prime numbers in an 
// array object.
template<size_t Size>
void concrt_count_primes(const array<int, Size>& a)
{
   if (a.size() == 0)
      return;

   combinable<size_t> counts;
   parallel_for_each(a.begin(), a.end(), [&counts](int n) 
   {
      if (is_prime(n)) {
         counts.local()++;
      }
   });

   wcout << L"found " << counts.combine(plus<size_t>()) 
         << L" prime numbers." << endl;
}

编译代码

复制该代码示例,并将其粘贴到 Visual Studio 项目中或名为 concrt-omp-count-primes.cpp 的文件中,然后在 Visual Studio 2010 命令提示符窗口中运行以下命令。

cl.exe /EHsc /openmp concrt-omp-count-primes.cpp

请参见

概念

并行算法

并行容器和对象

其他资源

从 OpenMP 迁移至并发运行时