Поддержка многопоточности в пользовательском приложении
Чтобы использовать интерфейсы ядра в нескольких потоках, для ядра должен быть установлен режим многопоточных вычислений не ниже mtm_SafeItems. По умолчанию в ядре установлен максимальный режим многопоточности mtm_Max.
Если пользовательское приложение использует интерфейсы ядра в нескольких потоках, оно обязано сообщать ядру о входе в каждый параллельный регион и о выходе из него. Для этого могут быть использованы класс ParallelRegionGuard (защитник параллельного региона в области видимости) или парные функции EnterParallelRegion и ExitParallelRegion.
Защита параллельного кода в пользовательском приложении
Класс ParallelRegionGuard сообщает ядру, что код в области видимости выполняется параллельно. Он должен использоваться для защиты параллельного кода.
Вместо класса ParallelRegionGuard следующая пара функций также может быть использована для нотификации ядра о границах параллельного региона кода:
Функция EnterParallelRegion сообщает ядру о входе в параллельный блок кода.
Функция ExitParallelRegion сообщает ядру о выходе из параллельного блока кода.
Использование ParallelRegionGuard или функций EnterParallelRegion и ExitParallelRegion является обязательным, если интерфейсы ядра используются в нескольких потоках.
Прежде чем начать использовать параллельные вычисления, нужно убедиться, что в ядре установлен режим многопоточности не ниже mtm_SafeItems (по умолчанию в ядре установлен максимальный режим многопоточности mtm_Max).
Примеры уведомления ядра о его использовании в параллельных вычислениях
ParallelRegionGuard должен вызываться один раз перед началом работы в нескольких потоках. Например:
// ... Последовательный код ...
if( Math::CheckMultithreadedMode( mtm_Items ) ) {
ParallelRegionGuard guard; // Работает в области видимости
std::thread t1( func1 );
std::thread t2( func2 );
t1.join();
t2.join();
}
// ... Последовательный код ...
То же самое можно сделать, используя пару функций EnterParallelRegion() и ExitParallelRegion() вместо ParallelRegionGuard:
// ... Последовательный код ...
if( Math::CheckMultithreadedMode( mtm_Items ) ) {
EnterParallelRegion();
std::thread t1( func1 );
std::thread t2( func2 );
t1.join();
t2.join();
ExitParallelRegion();
}
// ... Последовательный код ...
Интерфейсы ParallelRegionGuard, EnterParallelRegion и ExitParallelRegion должны использоваться, чтобы нотифицировать ядро о распараллеливании в пользовательском приложении. Эти нотификации нужны, чтобы обеспечить правильную работу механизмов потокобезопасности ядра.
Краткая справка по организации параллельных вычислений с использованием интерфейсов ядра C3D
Перед запуском параллельных вычислений приложение должно проверить, что установленный режим многопоточности ядра позволяет использовать параллельные вычисления. Чтобы использовать интерфейсы ядра в нескольких потоках, в ядре должен быть установлен режим многопоточных вычислений не ниже mtm_SafeItems.
Пример проверки режима ядра:
bool useParallel = Math::CheckMultithreadedMode( mtm_SafeItems );
При использовании параллельных вычислений пользовательское приложение обязано нотифицировать ядро о входе в параллельный регион и выходе из него.
Если используется параллельный цикл, то перед его началом нужно вызвать EnterParallelRegion, а после окончания – ExitParallelRegion.
Пример:
if( Math::CheckMultithreadedMode( mtm_Items ) ) { EnterParallelRegion(); #pragma omp parallel for for( ptrdiff_t i = 0; i < count; ++i ) { // Тело цикла } ExitParallelRegion(); }
Если интерфейсы ядра просто вызываются из разных потоков, то в каждом потоке перед вызовами интерфейсов ядра должен быть вызов EnterParallelRegion, а после окончания использования ядра – вызов ExitParallelRegion.
Пример:
// Поток 1: EnterParallelRegion(); // Вызовы интерфейсов ядра ExitParallelRegion(); // Поток 2: EnterParallelRegion(); // Вызовы интерфейсов ядра ExitParallelRegion();
После первого вызова EnterParallelRegion ядро начнет использовать многопоточные кэши, а после последнего вызова ExitParallelRegion вернется в базовый режим одного потока.
Не рекомендуется вызывать функции EnterParallelRegion и ExitParallelRegion без необходимости (в отсутствие многопоточности), так как использование многопоточных кэшей влечет за собой дополнительные затраты времени на получение кэшированных данных.