Как я могу справиться с гонкой данных в OpenMP?
Я пытаюсь использовать OpenMP для добавления чисел в массив. Ниже приведен мой код:
int* input = (int*) malloc (sizeof(int)*snum);
int sum = 0;
int i;
for(i=0;i<snum;i++){
input[i] = i+1;
}
#pragma omp parallel for schedule(static)
for(i=0;i<snum;i++)
{
int* tmpsum = input+i;
sum += *tmpsum;
}
это не дает правильного результата для sum
. Что случилось?
2 ответов
ваш код в настоящее время имеет гонки, поэтому результат неверен. Чтобы проиллюстрировать, почему это так, давайте используем простой пример:
вы работаете на 2 потоках, а массив -int input[4] = {1, 2, 3, 4};
. Вы инициализируете sum
до 0
правильно и готовы начать цикл. На первой итерации вашего цикла поток 0 и поток 1 читают sum
из памяти 0
, а затем добавить их элемент sum
, и записать его обратно в память. Однако, это означает, что поток 0 пытается писать sum = 1
в память (первый элемент 1
и sum = 0 + 1 = 1
), в то время как поток 1 пытается написать sum = 2
в память (второй элемент 2
и sum = 0 + 2 = 2
). Конечный результат этого кода зависит от того, какой из потоков завершается последним, и поэтому записывается в память последним, что является условием гонки. Не только это, но и в данном конкретном случае ни один из ответов, которые может дать код, не являются правильными! Есть несколько способов чтобы обойти это; я подробно остановлюсь на трех основных ниже:
#pragma omp critical
:
в OpenMP есть то, что называется
использовать reduction
п. (описание в MSDN).
int* input = (int*) malloc (sizeof(int)*snum);
int sum = 0;
int i;
for(i=0;i<snum;i++){
input[i] = i+1;
}
#pragma omp parallel for schedule(static) reduction(+:sum)
for(i=0;i<snum;i++)
{
sum += input[i];
}