#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. Тогда это не совсем глобально 😉 Для чего используется эта переменная? Это не будет работать, пока идентификатор не будет изменен в цикле