Критические секции

В очередь, сукины дети, в очередь!
М. А. Булгаков "Собачье сердце"
#pragma omp critical (name)

С помощью директивы critical мы можем указать участок кода, который будет исполняться только одним потоком в один момент времени. Если один из потоков начал выполнение критической секции с данным именем, то остальные потоки, начавшие выполнение этой же секции, будут заблокированы. Они будут ждать своей очереди. Как только первый поток завершит выполнение секции, один из заблокированных потоков войдёт в неё. Выбор следующего потока, который будет выполнять критическую секцию, будет случайным.

#include <omp.h>

void main()
{
 int x;
 x = 0;

    #pragma omp parallel shared(x) 
    {
        #pragma omp critical 
        x = x + 1;
    }  
}

Критические секции могут быть именованными или не именованными. В различных ситуациях улучшает производительность. Согласно стандарту все критические секции без имени, будут ассоциированы одним именем.
Присвоение имени позволит вам одновременно выполнять две и более критические секции одновременно.

#pragma omp critical  
{
    doworkA();
}
#pragma omp critical 
{
    doworkB();
}
// будет завершена секция с  doworkA() , а только потом  с doworkB()



#pragma omp critical (first) 
{
    doworkA();
}
#pragma omp critical (second) 
{
    doworkB();
}

//секции с doworkA () и doworkB() будут выполнены одновременно

Очень важно что бы имя критической секции не было названием системной функции или же было идентично уже использованному в проекте.

Есть случаи когда именовать нужно одним именем. Когда у вас в обоих критических секциях вывод в один и тот же файл или же вывод на экран.

#pragma omp critical
{
    cout << "Привет от потока № " << omp_get_thread_num()<<endl;
}

//omp_get_thread_num() - библиотечная функция которая возвращает номер потока.

Обработка вложенных критических секций, может создать условие для наступления взаимной блокировки.

Критические секции удобный инструмент для разграничения доступа к общим данным. Однако, критическая секция привносит в параллельную программу последовательный код, что снижает эффективность. Следует применять только по необходимости. Ниже пример модификации кода с критической секцией.

//Алгоритм поиска максимального элемента массива

#pragma omp parallel for 
for ( i = 0 ; i < N; ++i ) 
{ 
    #pragma omp critical 
    {
        if (arr[i] > max) max = arr[i]; 
    } 
}

//Мы можем вынести условие из критической секции
//т.к. условие будет положительным не каждой итерации

#pragma omp parallel for
for ( i = 0 ; i < N; ++i ) 
{ 
    #pragma omp flush(max) if (arr[i] > max) 
    {
        #pragma omp critical 
        { 
            if (arr[i] > max) max = arr[i];
        } 
    } 
}

Измененный код, будет более производительным.

Типичные ошибки:

  • Использование critical когда эффективнее использовать atomic

  • Большие объёмы работ внутри critical секции

  • Использование не нужной critical секции

results matching ""

    No results matching ""