OpenMP Deadlock с использованием omp_set_lock - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть функция со следующей общей структурой:

void a_generic_function(int N, int *arr, int *superarr)
{
  //some code
  for (int i = 0; i < N; i++)
  {
    omp_init_lock(&(lock[i])); //Initializes N locks, lock is allocated dynamic mem previously.
  }
  #pragma omp parallel shared(lock)
  {
    #pragma omp for
    {
      for (int i = 1; i <= N; i++)
      {
        //some code
        for (int j = arr[i-1]; j < arr[i]; i++) //where arr is size N+1
        {
          //some code
          for (int k = 0; k < temp; k++) //where temp < N
          {
            omp_set_lock(&(lock[subarr[k]])); //subarr is size <= N
            superarr[subarr[k]] += temp-1; //superarr is size = N. Temp is an int value.
            omp_unset_lock(&(lock[subarr[k]]));
          }
        }
      }
    }
  }
}

В этом коде есть только одна точка с ограничением на вход по потокам, которая должна быть немедленно разблокирована, как только критическая операция завершена, но эта функция часто блокируется. Я не могу понять, что вызвало бы это.

(Ради полноты: параллелизации вне этой функции нет)

1 Ответ

0 голосов
/ 10 апреля 2020

Слишком много "// некоторого кода", чтобы быть уверенным, но для меня проблема в том, что вы не отпускаете те же блокировки, которые вы установили, т.е. значение subarr[k] изменяется после вызова omp_set_lock и до omp_unset_lock. Одним из возможных решений было бы создание приватной переменной потока, например,

int n = subarr[k];
omp_set_lock(&lock[n]);
// do stuff
omp_unset_lock(&(lock[n]));

. Это гарантирует, что поток освобождает ту же блокировку, которую он установил.

В качестве бонуса: вы можете безопасно поставить #pragma omp parallel for на вашей инициализации блокировки l oop для повышения производительности.

...