Создание кода OpenMP с учетом графа зависимостей
У меня есть вопрос о том, как создать псевдокод OpenMP, если у вас есть определенный граф зависимостей. Итак, предположим, что у нас есть этот конкретный график:
Решение может быть что-то вроде этого:
#pragma omp parallel
{
#pragma omp single
{
A();
#pragma omp task B();
#pragma omp task C();
D();
#pragma omp taskwait
#pragma omp task E();
F();
}
}
Теперь дело в том, что, хотя приведенный выше код действительно успешно выполняет важный параллелизм, задача E должна ждать завершения задачи D, а задача F должна ждать завершения задачи B, что не требуется согласно графику.
Поэтому мой вопрос: может ли кто-нибудь предоставить мне псевдокод OpenMP, где E не будет ждать D, а F не будет ждать B для данного графа зависимостей?
1 ответ
Для этой цели стандарт OpenMP предлагает depend
пункт для task
директивы.
В вашем конкретном случае, я думаю, это можно использовать так:
#include <stdio.h>
int a, b, c;
void A() {
a = b = c = 1;
printf( "[%d]In A: a=%d b=%d c=%d\n", omp_get_thread_num(), a, b, c );
}
void B() {
a++;
sleep( 3 );
printf( "[%d]In B: a=%d\n", omp_get_thread_num(), a );
}
void C() {
b++;
sleep( 2 );
printf( "[%d]In C: b=%d\n", omp_get_thread_num(), b );
}
void D() {
c++;
sleep( 1 );
printf( "[%d]In D: c=%d\n", omp_get_thread_num(), c );
}
void E() {
a++;
sleep( 3 );
printf( "[%d]In E: a=%d, b=%d\n", omp_get_thread_num(), a, b );
}
void F() {
c++;
sleep( 1 );
printf( "[%d]In F: b=%d c=%d\n", omp_get_thread_num(), b, c );
}
int main() {
#pragma omp parallel num_threads( 8 )
{
#pragma omp single
{
#pragma omp task depend( out: a, b, c )
A();
#pragma omp task depend( inout: a )
B();
#pragma omp task depend( inout: b )
C();
#pragma omp task depend( inout: c )
D();
#pragma omp task depend( inout: a ) depend( in: b )
E();
#pragma omp task depend( inout: c ) depend( in: b )
F();
}
}
printf( "Finally a=%d b=%d c=%d\n", a, b, c );
return 0;
}
Как видите, я ввел некоторые переменные a
, b
а также c
который я использую, чтобы определить зависимости между задачами. Я также соответствующим образом изменяю их в вызове, хотя в этом нет необходимости (я сделал это только для того, чтобы показать, как обрабатывается поток).
И вот что я получаю на своей машине:
~/tmp$ gcc -fopenmp depend.c
~/tmp$ ./a.out
[6]In A: a=1 b=1 c=1
[7]In D: c=2
[2]In C: b=2
[6]In B: a=2
[2]In F: b=2 c=3
[6]In E: a=3, b=2
Finally a=3 b=2 c=3