您正在查找的功能已在名称下提出
多重依赖关系
by Vidal et al. in the International Workshop on OpenMP, 2015
(参见
here for an open access version
).
据我所知,这个功能还没有进入OpenMP任务中(到目前为止?),但你可以用
OmpSs
,这是OpenMP的先行者,也是该提案(以及更多)的实施者。
否则,由于依赖项编号需要在编译时定义,最糟糕的解决方法是编写(或生成)一个
switch
(或评级机构
SELECT CASE
对于Fortran),依赖项的数量,每个依赖项都有自己的单独pragma。
恐怕我对Fortran不太了解,但在C语言中,使用X宏和
_Pragma()
. 我认为GNU fortran使用的是C预处理器,所以希望您可以转置我曾经使用过的一些代码(否则您可能需要手工编写所有案例):
// L(n, X) = Ln(X) is a list of n macro expansions of X
#define L_EVALN(N, X) L ## N(X)
#define L(N, X) L_EVALN(N, X)
#define L1(X) X(1, b)
#define L2(X) L1(X) X(2, c)
#define L3(X) L2(X) X(3, d)
#define L4(X) L3(X) X(4, e)
#define L5(X) L4(X) X(5, f)
#define L6(X) L5(X) X(6, g)
#define L7(X) L6(X) X(7, h)
#define L8(X) L7(X) X(8, i)
#define L9(X) L8(X) X(9, j)
#define L10(X) L9(X) X(10, k)
#define L11(X) L10(X) X(11, l)
#define L12(X) L11(X) X(12, m)
#define L13(X) L12(X) X(13, n)
// Expand x, stringify, and put inside _Pragma()
#define EVAL_PRAGMA(x) _Pragma (#x)
#define DO_PRAGMA(x) EVAL_PRAGMA(x)
// X-macro to define dependecies on b{id} (size n{id})
#define OMP_DEPS(num, id) , [n_ ## id]b_ ## id
// X-macro to define symbols b{id} n{id} for neighbour #num
#define DEFINE_DEPS(num, id) \
double *b_ ## id = b[num]; \
int n_ ## id = nb[num];
// Calls each X-macros N times
#define N_OMP_DEPS(N) L(N, OMP_DEPS)
#define N_CALL_DEPS(N) L(N, CALL_DEPS)
#define N_DEFINE_DEPS(N) L(N, DEFINE_DEPS)
// defines the base task with 1 dependency on b_a == *b,
// to which we can add any number of supplementary dependencies
#define OMP_TASK(EXTRA) DO_PRAGMA(omp task depend(in: [n_a]b_a EXTRA))
// if there are N neighbours, define N deps and depend on them
#define CASE(N, ...) case N: \
{ \
N_DEFINE_DEPS(N) \
OMP_TASK(N_OMP_DEPS(N)) \
{ \
for (int i = 0; i < n; i++) b[i] = ... ; \
} \
} break;
int task(int n, int *nb, double **b)
{
double *b_a = b[0];
int nb_a = b[0];
switch(n)
{
CASE(1)
CASE(2)
CASE(3)
CASE(4)
}
}
这将生成以下代码(如果对其进行修饰):
int task(int n, int *nb, double **b)
{
double *b_a = b[0];
int nb_a = b[0];
switch (n)
{
case 1:
{
double *b_b = b[1];
int n_b = nb[1];
#pragma omp task depend(in: [n_a]b_a , [n_b]b_b)
{
for (int i = 0; i < n; i++)
b[i] = ... ;
}
} break;
case 2:
{
double *b_b = b[1];
int n_b = nb[1];
double *b_c = b[2];
int n_c = nb[2];
#pragma omp task depend(in: [n_a]b_a , [n_b]b_b , [n_c]b_c)
{
for (int i = 0; i < n; i++)
b[i] = ... ;
}
} break;
case 3:
{
double *b_b = b[1];
int n_b = nb[1];
double *b_c = b[2];
int n_c = nb[2];
double *b_d = b[3];
int n_d = nb[3];
#pragma omp task depend(in: [n_a]b_a , [n_b]b_b , [n_c]b_c , [n_d]b_d)
{
for (int i = 0; i < n; i++)
b[i] = ... ;
}
} break;
case 4:
{
double *b_b = b[1];
int n_b = nb[1];
double *b_c = b[2];
int n_c = nb[2];
double *b_d = b[3];
int n_d = nb[3];
double *b_e = b[4];
int n_e = nb[4];
#pragma omp task depend(in: [n_a]b_a , [n_b]b_b , [n_c]b_c , [n_d]b_d , [n_e]b_e)
{
for (int i = 0; i < n; i++)
b[i] = ... ;
}
} break;
}
}
虽然这很可怕,但这是一个解决办法,它的主要好处是:它可以工作。