あなたの答え、特にOpenMPに関するヒントをありがとう、それは確かに実行可能です. 完全に確実にするために、小さなプログラムを作成しました。これは、1 つのメイン C++ プログラムで呼び出される 1 つの Fortran 77 部分で構成されています (これは私の関心事です)。
fortran 77 ルーチンfunc.f :
subroutine set(ii, jj)
implicit none
include "func.inc"
integer ii, jj
integer OMP_GET_NUM_THREADS, OMP_GET_THREAD_NUM
i = ii + 1
j = jj
!$OMP CRITICAL
print *, OMP_GET_THREAD_NUM(), OMP_GET_NUM_THREADS(), i, j
!$OMP END CRITICAL
return
end
subroutine func(n, v)
implicit none
include "func.inc"
integer n, k
integer v(n)
do k = i, j
a = k + 1
b = a * a
c = k - 1
v(k) = b - c * c
enddo
return
end
インクルードファイルfunc.inc
integer i, j
integer a, b, c
common /mycom1/ i, j
!$OMP THREADPRIVATE(/mycom1/)
common /mycom2/ a, b, c
!$OMP THREADPRIVATE(/mycom2/)
そして最後に C++ プログラムmain.cpp :
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
#include<omp.h>
extern "C"
{
void set_(int*, int*);
void func_(int*, int*);
};
int main(int argc, char *argv[])
{
int nthread;
{
istringstream iss(argv[1]);
iss >> nthread;
}
int n;
{
istringstream iss(argv[2]);
iss >> n;
}
vector<int> a(n, -1);
#pragma omp parallel num_threads(nthread) shared(a)
{
const int this_thread = omp_get_thread_num();
const int num_threads = omp_get_num_threads();
const int m = n / num_threads;
int start = m * this_thread;
int end = start + m;
const int p = n % num_threads;
for (int i = 0; i < this_thread; ++i)
if (p > i) start++;
for (int i = 0; i <= this_thread; ++i)
if (p > i) end++;
#pragma omp critical
{
cout << "#t " << this_thread << " : [" << start
<< ", " << end << "[" << endl;
}
set_(&start, &end);
func_(&n, a.data());
}
cout << "[ " << a[0];
for (int i = 1; i < n; ++i)
cout << ", " << a[i];
cout << "]" << endl;
ostringstream oss;
for (int i = 1; i < n; ++i)
if ((a[i] - a[i - 1]) != int(4))
oss << i << " ";
if (! oss.str().empty())
cout << "<<!! Error occured at index " << oss.str()
<< " !!>>" << endl;
return 0;
}
コンパイル手順 (gcc バージョン 4.8.1):
gfortran -c func.f -fopenmp
g++ -c main.cpp -std=gnu++11 -fopenmp
g++ -o test main.o func.o -lgfortran -fopenmp
次のように起動できます。
./test 10 1000
どこ
- 最初の整数 (10) は、必要なスレッドの数です。
- 2 番目 (1000) は 1 つのベクトルの長さです。
このプログラムの目的は、このベクトルをスレッド間で分割し、各スレッドがその一部を埋めるようにすることです。
ベクトルの塗りつぶしは、fortran 77 内で行われます。
- setルーチンは、最初にスレッドによって管理される下限と上限を設定します。
- funcルーチンは、前の境界の間のベクトルを埋めます。
通常、エラーがなく、共通の Fortran 77 ブロックが共有されていない場合、最終的なベクトルは 4 * k の値 (k は 1 から 1000 まで) で満たされます。
プログラムをキャッチできませんでした。逆に、 func.incの fortran 77 OMP ディレクティブを削除すると、共通ブロックはプライベートではなくなり、多くのエラーが発生します。
結論として、最初の問題を解決するために必要な唯一のことは、共通ブロックのすぐ後ろに OMP ディレクティブを追加することです。これは、すべてが 1 つのインクルード ファイル (私のテストのように) にまとめられているため、それほど複雑ではありません。
これが役立つことを願っています。
よろしくお願いします。