.. role:: blue :class: blue Support of Multithreading in User Application ============================================= .. _Support_of_multithreading_in_user_application_: .. версия ядра: For using the kernel interfaces in several threads, the multithreading mode :blue:`mtm_SafeItems` or higher should be defined for the kernel. By default the kernel works in the maximal multithreading mode (:blue:`mtm_Max`). If the user application uses the kernel interfaces in parallel computation, it must notify the kernel about entering and exiting a parallel region. For that, the :blue:`ParallelRegionGuard` class (a scoped guard of a parallel region) or the pair of functions :blue:`EnterParallelRegion` and :blue:`ExitParallelRegion` can be used. Protection of Parallel Code in User Application ----------------------------------------------- The :blue:`ParallelRegionGuard` class notifies the kernel that code in the scope runs in parallel. It should be used to protect a parallel region. Instead of the :blue:`ParallelRegionGuard` class, the following pair of functions also can be used to notify the kernel about parallel region boundaries: - The **EnterParallelRegion** function notifies the kernel about entering a parallel region. - The **ExitParallelRegion** function notifies the kernel about exiting a parallel region. Interfaces :blue:`ParallelRegionGuard`, **EnterParallelRegion** and **ExitParallelRegion** must be used in cases when the kernel is used in several threads. Note that before starting to use parallel computing it is necessary to ensure that the multithreading mode :blue:`mtm_SafeItems` or higher is set in the kernel (by default the maximal multithreading mode :blue:`mtm_Max` is set). The Examples of Notifying the Kernel about its Use in Parallel Computing ------------------------------------------------------------------------- :blue:`ParallelRegionGuard` should be called one time before starting work in several threads. For example: .. code-block:: cpp // ... Sequential code ... if( Math::CheckMultithreadedMode( mtm_Items ) ) { ParallelRegionGuard guard; // works in the scope std::thread t1( func1 ); std::thread t2( func2 ); t1.join(); t2.join(); } .. code-block:: cpp // ... Sequential code ... The same can be done using a pair of functions :blue:`EnterParallelRegion` and :blue:`ExitParallelRegion` instead of :blue:`ParallelRegionGuard`: .. code-block:: cpp // ... Sequential code ... if( Math::CheckMultithreadedMode( mtm_Items ) ) { EnterParallelRegion(); std::thread t1( func1 ); std::thread t2( func2 ); t1.join(); t2.join(); ExitParallelRegion(); } // ... Sequential code ... The purpose of the :blue:`ParallelRegionGuard`, :blue:`EnterParallelRegion` and :blue:`ExitParallelRegion` interfaces is notifying the kernel about parallel calculations in a user application. These notifications are necessary to guarantee correct work of thread-safety mechanisms in the kernel. Quick Reference on Organizing Parallel cComputing Using C3D Interfaces --------------------------------------------------------------------- 1. Before running parallel calculations the application must check that the multithreading mode of the kernel allows parallel computing. To use kernel interfaces in several threads, the multithreading mode of the kernel must be set to at least :blue:`mtm_SafeItems`. Example of checking the kernel multithreading mode: *bool useParallel = Math::CheckMultithreadedMode( mtm_SafeItems );* 2. When using parallel calculations the user application must notify the kernel about entering and exiting a parallel region. If a parallel cycle is used, the application must call :blue:`EnterParallelRegion`\() before the cycle start and :blue:`ExitParallelRegion`\() after the cycle finish. Example: .. code-block:: cpp if( Math::CheckMultithreadedMode( mtm_Items ) ) { EnterParallelRegion(); #pragma omp parallel for for( ptrdiff_t i = 0; i < count; ++i ) { /* Cycle body */ } ExitParallelRegion(); } If the kernel interfaces are simply called from several threads, then in each thread :blue:`EnterParallelRegion` must be placed before the kernel calls and :blue:`ExitParallelRegion` must be placed after the kernel calls. Example: .. code-block:: cpp // Thread 1: EnterParallelRegion(); // The kernel calls ExitParallelRegion(); // Thread 2: EnterParallelRegion(); // The kernel calls ExitParallelRegion(); After the first call of :blue:`EnterParallelRegion` the kernel starts using multithreaded caches, and after the last call of :blue:`ExitParallelRegion` it returns to the base mode of sequential execution. 3. It is not recommended to call :blue:`ParallelRegionGuard`\(), :blue:`EnterParallelRegion`\() and :blue:`ExitParallelRegion`\() without need (in the absence of multithreading), because the use of multithreaded caches in sequential execution entails some time overhead of obtaining cached data.