Предположим, у меня есть цикл OpenMP 2.0 for, который выполняет некоторую операцию:
#pragma omp parallel for schedule(static)
for (int i = 0; i < lim; ++i)
{
// do something thread-safe
}
threadSafeFunc();
unSafeFunc();
Функтор threadSafeFunc
полностью потокобезопасен, поэтому вместо того, чтобы запускать его последовательно после завершения всех этих итераций, я хотел бы получить первый поток, который заканчивает выделение задач из цикла OpenMP, чтобы начать работать над ним, а затем для всех потоков ждать до unSafeFunc
в последовательном порядке.
Как мне это сделать?
Это может быть решением вашей конкретной проблемы:
#pragma omp parallel
{ // #1
#pragma omp for schedule(static) nowait
for (int i = 0; i < lim; ++i) // #2
{
// do something thread-safe
} // No implied barrier bue to the nowait clause
#pragma omp single
{ // #3
threadSafeFunc();
} // Implied barrier
} // End of parallel region
unSafeFunc();
Идея довольно проста: сначала вы открываете parallel
область в #1
. Внутри этой параллельной области вы используете две конструкции для работы:
#2
#3
Конструкция цикла (раздел 2.7.1 стандарта) имеет предложение nowait
, которое удаляет неявный барьер в конце цикла. Тогда single
конструкция (раздел 2.7.3):
... указывает, что связанный структурированный блок выполняется только одним из потоков в команде (не обязательно основным потоком) в контексте его неявной задачи. Другие потоки в команде, которые не выполняют блок, ждут неявного барьера в конце сингла...
Комбинация двух конструкций гарантирует, что первый поток, завершивший свою работу в цикле, войдет в single
конструкцию и выполнит threadSafeFunc()
. Затем все потоки будут синхронизироваться с подразумеваемым барьером и соединяться с master
потоком. На этом этапе будет продолжаться только master
поток и выполнить unSafeFunc()
.