Я новый пользователь openmp, и я пытаюсь распараллелить часть моей программы и использую блокировки для двумерного массива. Я не буду вдаваться в подробности моей настоящей проблемы, а вместо этого расскажу о следующем упрощенном примере:
Допустим, у меня есть огромная группа частиц N >> 1, чьи их координаты x, y хранятся в некоторой структуре данных. Я хочу создать 2-мерный счетчик, который будет представлять сетку и подсчитывать все частицы в каждой ячейке сетки:
count [j] [k] + = 1 (для соответствующего j, k каждой частицы, согласно его значениям x, y)
Использование блокировок является естественным выбором (2D-массив имеет размер 100×100 и выше, поэтому, когда у вас есть 20-ядерный компьютер, шансы двух потоков одновременно обновить элемент массива по-прежнему довольно низки). Соответствующие части кода:
// определить 2d блокировку:
omp_lock_t **count_lock;
count_lock = new omp_lock_t* [J+1];
for(j=0;j<=J;j++) {
count_lock[j]=new omp_lock_t[K+1];
memset(count_lock[j],0,(K+1)*sizeof(omp_lock_t));
}
// инициализация:
for(j=0;j<=J;j++)
for(k=0;k<=K;k++){
omp_init_lock(&(count_lock[j][k]));
omp_unset_lock(&(count_lock[j][k]));
}
// используя блокировку (после определения правого j, k):
omp_set_lock(&(count_lock[j][k]));
count[j][k] += 1;
omp_unset_lock(&(count_lock[j][k]));
// уничтожаем блокировку:
for(i=0;i<=J;i++)
for(j=0;j<=K;j++)
omp_destroy_lock(&(count_lock[i][j]));
for (j=0; j<=J; j++)
delete[] count_lock[j];
delete[] count_lock;
Частицы делятся на группы по 500 частиц. каждая группа представляет собой связанный список частиц, и все группы частиц также образуют связанный список. Параллелизация происходит из распараллеливания цикла for, который проходит по группам частиц.
По какой-то причине я не могу понять, что это правильно … никакого улучшения производительности не получается, и симуляция застревает после нескольких итераций.
Я попытался использовать «атомарный», но он дал еще худшую производительность, чем последовательный код. Другой вариант, который я попробовал, — создать частный 2D-массив для каждого потока, а затем суммировать их. Таким образом, я получил некоторые улучшения, но это довольно дорого, и я надеюсь, что есть лучший способ.
Спасибо!
Задача ещё не решена.
Других решений пока нет …