1. ホーム
  2. c++

[解決済み] OpenMPにおける配列の削減

2022-02-12 09:37:31

質問

以下のプログラムを並列化しようとしているのですが、配列での削減の仕方がわかりません。無理なのは分かっているのですが、他に方法はないでしょうか?ありがとうございます。(間違ったmに対するreductionを追加してしまいましたが,やり方をアドバイスしていただきたいです)

#include <iostream>
#include <stdio.h>
#include <time.h>
#include <omp.h>
using namespace std;

int main ()
{
  int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};
  int S [10];

  time_t start_time = time(NULL);
  #pragma omp parallel for private(m) reduction(+:m)
  for (int n=0 ; n<10 ; ++n ){
    for (int m=0; m<=n; ++m){
      S[n] += A[m];
    }
  }
  time_t end_time = time(NULL);
  cout << end_time-start_time;

  return 0;
}

解決方法は?

OpenMPで配列の縮小を行うことは可能です。 Fortranでは、そのためのコンストラクトも用意されています。 C/C++では、自分でやる必要があります。 ここでは、その方法を2つ紹介します。

最初の方法は、プライベート版の S を各スレッドに適用し、並列に充填した後、それらを S をクリティカルセクションで表示します(以下のコードを参照してください)。 2番目の方法は、次元数10*nthreadsの配列を作成する。 この配列を並列に埋め、それを S クリティカルセクションを使用せずに 2番目の方法はもっと複雑で、特にマルチソケット・システムでは注意しないとキャッシュの問題が発生する可能性があります。 詳しくはこちらをご覧ください。 OpenMPでクリティカルセクションを使用せずにヒストグラムを埋める(配列の縮小)並列処理

最初の方法

int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};
int S [10] = {0};
#pragma omp parallel
{
    int S_private[10] = {0};
    #pragma omp for
    for (int n=0 ; n<10 ; ++n ) {
        for (int m=0; m<=n; ++m){
            S_private[n] += A[m];
        }
    }
    #pragma omp critical
    {
        for(int n=0; n<10; ++n) {
            S[n] += S_private[n];
        }
    }
}

第二の方法

int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};
int S [10] = {0};
int *S_private;
#pragma omp parallel
{
    const int nthreads = omp_get_num_threads();
    const int ithread = omp_get_thread_num();

    #pragma omp single 
    {
        S_private = new int[10*nthreads];
        for(int i=0; i<(10*nthreads); i++) S_private[i] = 0;
    }
    #pragma omp for
    for (int n=0 ; n<10 ; ++n )
    {
        for (int m=0; m<=n; ++m){
            S_private[ithread*10+n] += A[m];
        }
    }
    #pragma omp for
    for(int i=0; i<10; i++) {
        for(int t=0; t<nthreads; t++) {
            S[i] += S_private[10*t + i];
        }
    }
}
delete[] S_private;