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