Я пытаюсь реализовать алгоритм суммы префиксов в C с использованием OpenMP, и я застрял.
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
int main(int argc, char* argv[])
{
int p = 5;
int X[5] = { 1, 5, 4, 2, 3 };
int* Y = (int*)malloc(p * sizeof(int));
for (int i = 0; i < p; i++)
printf("%d ", X[i]);
printf("\n");
Y[0] = X[0];
int i;
#pragma omp parallel for num_threads(4)
for (i = 1; i < p; i++)
Y[i] = X[i - 1] + X[i];
int k = 2;
while (k < p)
{
int i;
#pragma omp parallel for
for (i = k; i < p; i++)
Y[i] = Y[i - k] + Y[i];
k += k;
}
for (int i = 0; i < p; i++)
printf("%d ", Y[i]);
printf("\n");
system("pause");
return 0;
}
Что должен делать этот код?
Input numbers are in
X
,
output numbers are (prefixes) inY
and the number count isp
.
X = 1, 5, 4, 2, 3
Этап I.
Y[0] = X[0];
Y[0] = 1
II этап.
int i;
#pragma omp parallel for num_threads(4)
for (i = 1; i < p; i++)
Y[i] = X[i - 1] + X[i];
Пример:
Y[1] = X[0] + X[1] = 6
Y[2] = X[1] + X[2] = 9
Y[2] = X[2] + X[3] = 6
Y[4] = X[3] + X[4] = 5
III этап.(где я застрял)
int k = 2;
while (k < p)
{
int i;
#pragma omp parallel for
for (i = k; i < p; i++)
Y[i] = Y[i - k] + Y[i];
k += k;
}
Пример:
k = 2
Y[2] = Y[0] + Y[2] = 1 + 9 = 10
Y[3] = Y[1] + Y[3] = 6 + 6 = 12
Y[4] = Y[2] + Y[4] = 10 + 5 = 15
Над 10 + 5 = 15
должно быть 9 + 5 = 14
, но Y[2]
было перезаписано другим потоком. Я хочу использовать то Y[2]
, что было до начала цикла for.
Пример:
k = 4
Y[4] = Y[0] + Y[4] = 1 + 15 = 16
Результат:1, 6, 10, 12, 16
. Ожидаемый хороший результат:1, 6, 10, 12, 15
.
Above the
10 + 5 = 15
should be9 + 5 = 14
, but theY[2]
was overwritten by another thread. I want to use thatY[2]
what was before the for-loop started.
С OpenMP вам всегда нужно учитывать, подходит ли ваш код для последовательного случая с одним потоком, потому что
Ваш код не является правильным последовательно. Кажется, вы можете исправить это, запустив проблемный цикл назад, от i
= p - 1
к k
, но на самом деле этого недостаточно для параллельной работы.
Лучше всего, по-видимому, накапливать ваши частичные результаты в массиве, отличном от результатов предыдущего цикла. Например, вы можете переключаться между X
и Y
в качестве источника данных и результата, при этом небольшой указатель будет возиться, чтобы смазать итерационные колеса. Или вы можете сделать это немного проще, используя 2D-массив вместо отдельных X и Y.
ОБНОВЛЕНИЕ для Этапа III.
int num_threads = 8;
int k = 2;
while (k < p)
{
#pragma omp parallel for ordered num_threads(k < num_threads ? 1 : num_threads)
for (i = p - 1; i >= k; i--)
{
Y[i] = Y[i - k] + Y[i];
}
k += k;
}
Приведенный выше код решил мою проблему. Теперь он работает параллельно, за исключением первых нескольких раундов.
Если у вас есть компилятор OpenMP 5.0, вам не нужно делать ничего из этого, так как OpenP 5.0 имеет директиву "scan"... (Раздел 2.9.6 на стр. 132 стандарта, который вы можете загрузить с openmp.org, если будете следовать твой нос).