Директивы C OpenMP для параллельного цикла for?

#c #openmp

#c #openmp

Вопрос:

Я пытаюсь OpenMP для определенного фрагмента кода. Не уверен, нуждается ли фрагмент в обновлении, возможно, он настроен слишком жестко для последовательной реализации. В любом случае, вот (псевдо-) код, который я пытаюсь распараллелить:

 #pragma omp parallel for private(id, local_info, current_local_cell_id, local_subdomain_size) shared(cells, current_global_cell_id, global_id)
for(id = 0; id < grid_size;   id) {
   local_info = cells.get_local_subdomain_info(id);
   local_subdomain_size = local_info.size();
   ...do other stuff...
   do {
      current_local_cell_id = cells.get_subdomain_cell_id(id);
      global_id.set(id, current_global_cell_id   current_local_cell_id);
   } while(id < local_subdomain_size amp;amp;   id);
   current_global_cell_id  = local_subdomain_size;
}
  

Это имеет полный смысл (после некоторого просмотра) в последовательном смысле, что также может означать, что его необходимо переписать для OpenMP. Меня беспокоит то, что current_local_cell_id и local_subdomain_size являются частными, но current_global_cell_id и global_id являются общими.

Следовательно, оператор current_global_cell_id = local_subdomain_size после внутреннего цикла:

 do {
  ...
} while(...)
current_global_cell_id  = local_subdomain_size;
  

Я подозреваю, что это может привести к ошибкам в настройке OpenMP. Я был бы очень признателен, если бы кто-нибудь из экспертов OpenMP мог предоставить некоторые указания на любую из специальных директив OMP, которые я могу использовать для внесения минимальных изменений в код, но при этом использовать OpenMP для такого типа цикла for .

Ответ №1:

Я не уверен, что понимаю ваш код. Тем не менее, я думаю, вы действительно хотите какое-то параллельное накопление.

Вы могли бы использовать шаблон, подобный

  size_t total = 0;
 #pragma omp parallel for shared(total) reduction ( :total)
 for (int i=0; i<MAXITEMS; i  )
 {
      total  = getvalue(i); // TODO replace with your logic
 }

 // total has been 'magically' combined by OMP
  

В связи с этим, когда вы используете gcc, вы можете просто использовать __gnu_parallel::accumulate выпадающую замену for std::accumulate , которая делает exactly то же самое. См. Главу 18. Параллельный режим

  size_t total = __gnu_parallel::accumulate(c.begin(), c.end(), 0, amp;myvalue_accum);
  

Вы даже можете выполнить компиляцию, с -D_GLIBCXX_PARALLEL помощью которой все используемые std алгоритмы будут автоматически распараллеливаться, если это возможно. Не используйте это, если вы не знаете, что делаете! Часто производительность просто страдает, и вероятность появления ошибок из-за неожиданного параллелизма реальна

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

1. добавлены подсказки по параллельному режиму GNU

Ответ №2:

изменение идентификатора внутри цикла неверно. Невозможно отправить цикл в другой поток, поскольку шаг цикла не дает предсказуемого значения id.

Почему вы используете идентификатор внутри этого цикла do while?

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

1. Вздох! Возможно, вы правы. Я надеялся избежать этого изменения. Но я думаю, что если бы я сделал current_global_cell_id также закрытым, он все равно мог бы работать, нет?

2. Тогда это не совсем глобально 😉 Для чего используется эта переменная? Это не будет работать, пока идентификатор не будет изменен в цикле