правильное использование встроенной функции и openmp

#c #loops #openmp

#c #циклы #openmp

Вопрос:

у меня есть цикл for, который вызывает внутреннюю функцию :

 some variables
for(int i=0; i< 10000000; i  )
    func(variables)
  

По сути, func получает ссылку на некоторый массив A и вставляет значения в A[i] — поэтому я уверен
, что каждый вызов func фактически пытается вставить значение в другое место в A, а все остальные входные переменные остаются такими же, какими они были до цикла for . Таким образом, функция потокобезопасна.

Могу ли я безопасно изменить код на

 some variables
#pragma omp parallel for
for(int i=0; i< 10000000; i  )
    func(variables)
  

Из того, что я понимаю из руководств по openmp, этого недостаточно — поскольку библиотеки openmp не будут знать, что переменные, переданные func, действительно потокобезопасны, и поэтому это приведет к попыткам выполнить синхронизацию, что замедлит работу, и мне нужно будет объявить переменные закрытыми и т. Д. Но на самом деле, при попытке использовать приведенный выше код, кажется, что он работает действительно быстрее и параллельно — это так, как ожидалось? Я просто хотел убедиться, что я ничего не упустил.

Объявление функции :

  func(int i, int client_num, const vector<int>amp; vec)
  

Комментарии:

1. Можете ли вы предоставить полное объявление функции (переменных), поскольку ответ будет зависеть от объявления.

2. я добавил в свой вопрос (упрощенное) объявление функции. Кроме того, дальнейшие проверки, похоже, показывают, что на самом деле моя программа с openmp дает разные результаты, чем без — все еще не уверен, что и где действует по-другому.

Ответ №1:

Прежде всего, OpenMP не может волшебным образом определить зависимость от вашего кода. Вы несете ответственность за правильность распараллеливания кода.

Для безопасного распараллеливания цикла for func не должно быть зависимостей от потока, переносимого циклом, или зависимости между итерациями, особенно для шаблона чтения после записи. Кроме того, вы должны проверить, нет ли статических переменных. (На самом деле, гораздо сложнее записать условия безопасного распараллеливания в этом коротком ответе.)


В вашем описании func говорится, что func переменная будет записана в другое место. Если это так, вы можете безопасно распараллеливать, помещая pragma omp parallel for , если только другие вычисления не имеют зависимостей, запрещающих распараллеливание.

Ваш прототип func : func(int i, int client_num, const vector<int>amp; vec)

Существует vector , но это константа, поэтому vec не должно иметь никакой зависимости. Одновременное чтение из разных потоков безопасно.

Однако вы говорите, что результат отличается. Это означает, что что-то было не так. Невозможно сказать, в чем проблемы. Показ прототипа функции никогда не помогает; нам нужно знать, какие вычисления выполняются func .

Тем не менее, некоторые шаги для диагностики:

  • Проверьте зависимость в своем коде. У вас не должно быть зависимостей, показанных ниже. Обратите внимание, что массив A имеет циклическую зависимость, которая предотвратит распараллеливание:

for (int k = 1; k <N; k) A[k] = A[k-1] 1;

  • Проверка func является повторной или потокобезопасной. В основном, статические и глобальные переменные могут убить ваш код. Если это так, вы можете решить эту проблему путем приватизации. В OpenMP вы можете объявить эти переменные в private предложении. Кроме того, в OpenMP есть threadprivate pragma.

Ответ №2:

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

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