- •Оглавление
- •Директивы
- •Примеры
- •Примеры
- •Примеры
- •Примеры
- •Примеры
- •Пример
- •Примеры
- •Примеры
- •Примеры
- •Синхронизация
- •Синхронизация
- •Пример
- •Пример
- •Пример
- •Пример
- •Пример
- •Пример
- •Пирмер
- •Пример условной компиляции
- •Вопросы
- •Пример условной компиляции
- •Терминология
- •Терминология
- •Терминология
- •Терминология
- •Терминология
- •Терминология
- •Терминология
- •Терминология
- •Конец
Пример
Задача: Распараллелить следующий цикл for (i=0; i < NumElements; i++)
{
array[i] = StartVal;
StartVal++;
В}исходном виде циклсодержит зависимость данных, что делает невозможным его распараллеливание без внесения изменений.
Примеры
Новый цикл заполняет массив таким же образом, но в нем отсутствуют зависимости данных.
#pragma omp parallel for
for (i=0; i < NumElements; i++)
{
array[i] = StartVal + i;
}
ОбратитеПримерывнимание, что данный код не на 100% совпадает с первоначальным, поскольку отсутствуетприращение переменной StartVal.
В результате после завершения параллельного цикла эта переменная будет иметь значение, отличное от того, которое получается в последовательной версии. Если значение StartVal используется после цикла, требуется дополнительный оператор,
Примеры
//Thisworksandisidenticaltotheserial version.
#pragmaompparallelfor for(i=0;i<NumElements;i++)
{
array[i]=StartVal+i;
}
StartVal+=NumElements;
Базовыеконструкции
Директиваparallel
Чтобыпродемонстрироватьзапуск несколькихпотоковраспараллелим следующий блоктекста:
#pragma omp parallel |
|
for(d1 = 0; d1 <= 9; d1++) |
|
for(d2 = 0; d2 <= 9; d2++) |
|
for(d3 = 0; d3 <= 9; d3++) |
|
for(d4 = 0; d4 <= 9; d4++) |
|
for(d5 = 0; d5 <= 9; d5++) |
|
for(d6 = 0; d6 <= 9; d6++) |
|
if(d1 + d2 + d3 == d4 + d5 + d6) |
|
iResult++; |
62 |
Базовыеконструкции
Директиваparallel
Привыполнениипрограммыполучен неверныйрезультат:
•Приверномвыполнениипрограммы количество«счастливыхбилетиков» должно быть55252шт.:
63
Базовыеконструкции
Директиваfor Директива
#pragma omp for
сообщает, чтопривыполнении циклаfor впараллельномрегионе итерациицикладолжныбыть распределенымеждупотоками группы
64
Базовыеконструкции
Директиваfor
Сдобавлениемдирективыfor получим:
#pragma omp parallel for |
|
for(d1 = 0; d1 <= 9; d1++) |
|
for(d2 = 0; d2 <= 9; d2++) |
|
for(d3 = 0; d3 <= 9; d3++) |
|
for(d4 = 0; d4 <= 9; d4++) |
|
for(d5 = 0; d5 <= 9; d5++) |
|
for(d6 = 0; d6 <= 9; d6++) |
|
if(d1 + d2 + d3 == d4 + d5 + d6) |
|
iResult++; |
65 |
Базовыеконструкции
Директивыprivate иshared
Относительнопараллельных регионовданныемогут быть общими
(shared)иличастными(private)
Частныеданныепринадлежатпотоку имогут бытьмодифицированытолько им
Общиеданныедоступнывсем потокам
66
Базовыеконструкции
Директивыprivate иshared
Врассматриваемомранеепримере переменныеd1-d6былиобщими
…
if(d1 + d2 + d3 == d4 + d5 + d6)
…
•Врезультатепеременныеначнут использоватьсявсемипотоками одновременно,чтоприведеткгонкам
67
Базовыеконструкции
Директивыprivate иshared
Чтобысделатьпеременнуюдлякаждого потокачастной(private)можно воспользоватьсядирективойprivate:
68
Базовыеконструкции
Директивыprivate иshared
#pragma omp parallel for private(d1,d2,d3,d4,d5,d6)
for(d1 = 0; d1 <= 9; d1++) for(d2 = 0; d2 <= 9; d2++) for(d3 = 0; d3 <= 9; d3++) for(d4 = 0; d4 <= 9; d4++) for(d5 = 0; d5 <= 9; d5++) for(d6 = 0; d6 <= 9; d6++)
if(d1 + d2 + d3 == d4 + d5 + d6) iResult++;
69
Базовыеконструкции
Директиваatomic
Данноераспараллеливаниенекорректно,таккак впроцессеработынесколькопотоковпытаются
одновременнообращатьсякпеременнойiResult длячтенияизаписи:
#pragma omp parallel for |
|
private(d1,d2,d3,d4,d5,d6) |
|
for(d1 = 0; d1 <= 9; d1++) |
|
for(d2 = 0; d2 <= 9; d2++) |
|
for(d3 = 0; d3 <= 9; d3++) |
|
for(d4 = 0; d4 <= 9; d4++) |
|
for(d5 = 0; d5 <= 9; d5++) |
|
for(d6 = 0; d6 <= 9; d6++) |
|
if(d1 + d2 + d3 == d4 + d5 + d6) |
70 |
Базовыеконструкции
Директиваatomic
Внекорректностираспараллеливания такжеможноубедитьсянапрактике, запустивдемонстрационныйкод:
71
Базовыеконструкции
Директиваatomic
Сприменениемдирективыatomic код будетвыглядетьтак:
#pragma omp parallel for |
|
private(d1,d2,d3,d4,d5,d6) |
|
for(d1 = 0; d1 <= 9; d1++) |
|
for(d2 = 0; d2 <= 9; d2++) |
|
for(d3 = 0; d3 <= 9; d3++) |
|
for(d4 = 0; d4 <= 9; d4++) |
|
for(d5 = 0; d5 <= 9; d5++) |
|
for(d6 = 0; d6 <= 9; d6++) |
|
if(d1 + d2 + d3 == d4 + d5 + d6) |
|
#pragma omp atomic |
72 |
Базовыеконструкции
Директиваatomic
Данноерешениедаеткорректный результат:
•ноявляетсякрайненеэффективным. Скоростьработыприведенногокода будетниже,чемскорость последовательноговарианта
73
Базовыеконструкции
Директиваreduction Форматдирективы:
reduction(оператор:список)
Возможные |
|
|
Список— |
|
|||
операторы: |
|
|
перечисляет |
o "+","*","-","&" |
|
|
именаобщих |
|
|
переменных(тип |
|
o "|","^" |
|
|
|
|
|
float, intилиlong) |
|
o "&&","||" |
|
|
|
|
|
74
Базовыеконструкции
Директиваreduction
Принципработы:
1.Длякаждойпеременнойсоздаются локальныекопии вкаждомпотоке
2.Локальныекопии инициализируются соответственнотипуоператора
3.Надлокальнымикопиями переменных послевыполнениявсех операторов параллельнойобластивыполняется заданныйоператор
75
Базовыеконструкции
Директиваreduction
Теперьсиспользованием«reduction», эффективноработающийкод приметвид:
#pragma omp parallel for private(d1,d2,d3,d4,d5,d6) reduction(+:iResult)
for(d1 = 0; d1 <= 9; d1++) for(d2 = 0; d2 <= 9; d2++) for(d3 = 0; d3 <= 9; d3++) for(d4 = 0; d4 <= 9; d4++) for(d5 = 0; d5 <= 9; d5++) for(d6 = 0; d6 <= 9; d6++)
if(d1 + d2 + d3 == d4 + d5 + d6) iResult++;
76
КострукцииOpenMP
конструкции длясозданияпотоков
(директиваparallel),
конструкции распределенияработы междупотоками(директивыDO/forи section),
конструкции дляуправленияработой с данными(выраженияsharedиprivateдля определенияклассапамятипеременных),
77
КострукцииOpenMP
конструкции длясинхронизациипотоков
(директивыcritical,atomicиbarrier),
процедурыбиблиотекиподдержки временивыполнения(например, omp_get_thread_num),
переменныеокружения(например, OMP_NUM_THREADS).
78
Конструкциидлясозданияпотоков:
директиваparallel
#pragma omp parallel опция[[[,] опция]...]
структурированный блок
Возможныеопции:
if(условие)– выполнениепараллельной области поусловию.Вхождениев параллельнуюобласть осуществляется только привыполнениинекоторого условия.Еслиусловиеневыполнено,то директиванесрабатываетипродолжается обработка программывпрежнемрежиме;
79
Конструкциидлясозданияпотоков: директиваparallel
Выполнениепараллельнойобласти по условию.
#pragma omp parallel if (x)
80
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
num_threads(целочисленноевыражение)– явноезаданиеколичестванитей,которые будутвыполнять параллельнуюобласть;
поумолчаниювыбираетсяпоследнее значение,установленное спомощью функцииomp_set_num_threads(),или значениепеременной
OMP_NUM_THREADS;
81
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
default(shared|none)– всемпеременнымв параллельной области,которым явноне назначенкласс,будетназначенкласс shared;none означает,чтовсем переменнымвпараллельнойобласти класс долженбытьназначенявно;
82
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
private(список) – задаётсписок переменных,для которых порождается локальная копия вкаждой нити;начальное значениелокальныхкопийпеременныхиз списканеопределено;
83
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
firstprivate(список)– задаётсписок переменных,для которых порождается локальная копия вкаждой нити;локальные копиипеременныхинициализируются значениямиэтихпеременныхвнитимастере;
84
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
shared(список)– задаётсписок переменных,общихдлявсехнитей;
85
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
copyin(список)– задаётсписок переменных,объявленныхкак threadprivate,которые привходев параллельнуюобласть инициализируются значениямисоответствующихпеременных внити-мастере;
86
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
reduction(оператор:список) – задаёт оператор исписокобщихпеременных;
длякаждой переменнойсоздаются локальные копиивкаждой нити;
87
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
reduction(оператор:список)
локальныекопииинициализируются соответственно типуоператора(для аддитивныхопераций– 0илиего аналоги,длямультипликативных операций– 1илиеёаналоги);
88
Конструкциидлясозданияпотоков: директиваparallel
Возможныеопции:
reduction(оператор:список)
надлокальными копиямипеременных послевыполнениявсехоператоров параллельной областивыполняется заданныйоператор;
порядоквыполненияоператоров не определён,поэтому результатможет отличаться отзапускакзапуску.
89
Конструкциидлясозданияпотоков: директиваparallel
Привходевпараллельнуюобласть порождаются новые
OMP_NUM_THREADS-1 нитей,каждая нитьполучаетсвойуникальныйномер, причёмпорождающая нитьполучает номер0истановитсяосновной нитью группы(“мастером”).
90
Конструкциидлясозданияпотоков: директиваparallel
Остальныенитиполучаютвкачестве номерацелыечислас1до
OMP_NUM_THREADS-1. Количество нитей,выполняющихданную параллельнуюобласть, остаётся неизменнымдомоментавыходаиз области.
91
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
private(список)– задаётсписок переменных,для которых порождается локальная копия вкаждой нити; начальноезначениелокальных копий переменныхизсписканеопределено;
103
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
firstprivate(список)– задаётсписок переменных,для которых порождается локальная копия вкаждой нити; локальные копиипеременных инициализируютсязначениямиэтих переменныхвнити-мастере;
104
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
lastprivate(список)– переменным, перечисленнымвсписке,присваивается результатспоследнеговиткацикла;
105
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
reduction(оператор:список) – задаёт оператор исписокобщихпеременных; длякаждой переменнойсоздаются локальные копиивкаждой нити; локальныекопииинициализируются соответственно типуоператора;
106
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
schedule(type[,chunk]) – опциязадаёт,
какимобразом итерациицикла распределяютсямеждунитями;
107
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
collapse(n)– опцияуказывает,чтоn последовательныхтесновложенных цикловассоциируетсясданной директивой;
108
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
collapse(n)–
еслиопцияcollapseнезадана,то директиваотносится только кодному непосредственноследующемузаней циклу;
109
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
ordered– опция,говорящая отом, чтов циклемогутвстречатьсядирективы ordered;вэтомслучаеопределяетсяблок внутрителацикла,который должен выполнятьсявтом порядке,вкотором итерацииидутвпоследовательномцикле;
110
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
nowait– вконцепараллельного цикла происходитнеявнаябарьерная синхронизацияпараллельноработающих нитей:ихдальнейшеевыполнение происходиттолько тогда, когдавсеони достигнутданнойточки;
111
Опциидирективыfor
#pragmaompforопция[[[,] опция]... ]
циклfor Возможныеопции:
nowait–
есливподобной задержкенет необходимости,опцияnowait позволяет нитям,ужедошедшимдоконцацикла, продолжить выполнениебез синхронизациисостальными.
112
Конструкциираспределенияработы междупотоками:директиваsingle
Есливпараллельнойобласти какой-либо участоккодадолженбытьвыполненлишь одинраз,тоегонужновыделить директивойsingle.
#pragmaompsingleопция[[[,]опция]...]
структурированный блок
113
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
private(список) – задаётсписок переменных,для которых порождается локальная копия в каждой нити;начальноезначение локальных копийпеременныхиз списканеопределено;
114
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
firstprivate(список)– задаётсписок переменных,для которых порождается локальная копия в каждой нити;локальные копии переменныхинициализируются значениямиэтихпеременныхвнитимастере;
115
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
copyprivate(список)– послевыполнения нити,содержащейконструкциюsingle, новыезначенияпеременныхсписка будутдоступнывсемодноименным частнымпеременным(privateи firstprivate),описаннымвначале параллельнойобластиииспользуемым всемиеёнитями;.
116
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
copyprivate(список)–
опциянеможетиспользоваться совместносопциейnowait;
переменныесписканедолжныбыть перечисленывопцияхprivateи firstprivateданнойдирективыsingle;
117
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
nowait– послевыполнениявыделенного участкапроисходитнеявнаябарьерная синхронизацияпараллельно работающихнитей:ихдальнейшее выполнениепроисходиттолько тогда, когда всеонидостигнутданнойточки;
118
Конструкциираспределенияработы междупотоками:директиваsingle
Возможныеопции:
nowait–
есливподобной задержкенет необходимости,опцияnowait позволяет нитям,ужедошедшимдоконцаучастка, продолжить выполнениебез синхронизациисостальными.
.
119
Конструкциираспределенияработы междупотоками:директиваsingle
Впараллельныхрегионахчасто встречаютсяблокикода, доступ ккоторым желательнопредоставлять только одному потоку, – например,блокикода, отвечающиезазаписьданныхвфайл.
120
Конструкциираспределенияработы междупотоками:директиваsingle
Вомногихтакихситуацияхнеимеет значения,какой потоквыполниткод, важнолишь,чтобыэтотпоток был единственным.Для этого вOpenMPтакже служитдирективаsingle.
121
Конструкциираспределенияработы междупотоками:директиваsingle
Какаяименнонитьбудетвыполнять выделенныйучастокпрограммы,не специфицируется.Однанитьбудет выполнять данныйфрагмент,авсе остальные нитибудутожидать завершения еёработы,еслитолько неуказанаопция nowait.
.
122
Конструкциираспределенияработы междупотоками:директиваsingle
Следующийпримериллюстрирует применениеопцииcopyprivate.
Вданномпримерепеременнаяn объявленавпараллельной областикак локальная.
Каждаянитьприсвоитпеременнойn значение,равноесвоемупорядковому номеру,инапечатаетданноезначение.
123
Конструкциираспределенияработы междупотоками:директиваsingle
Вобластиsingleоднаизнитейприсвоит переменнойnзначение100,инавыходеиз области этозначениебудетприсвоено переменнойnнавсехнитях.
Вконцепараллельной областизначениеn печатаетсяещёразинавсехнитяхоно равно100.
124
Конструкциираспределенияработы междупотоками:директиваsingle
#include <stdio.h> #include <omp.h>
intmain(int argc,char*argv[])
{
intn;
#pragmaompparallelprivate(n)
{
n=omp_get_thread_num(); printf("Значениеnначало():%d\n",n);
125
Конструкциираспределенияработы междупотоками:директиваsingle
#pragmaompsinglecopyprivate(n)
{
n=100;
}
printf("Значениеnконец():%d\n",n);
}
}
126
Конструкциираспределенияработы междупотоками:директиваsingle
Ограничениядлядирективыsingle следующие:
опцияcopyprivateнедолжна использоватьсявместесопциейnowait;
только однаопцияnowaitможетбыть использованавдирективеsingle;
исключениевобласти single должно быть обработанно врамкаходной области single,однойитойженитью.
127
Конструкциираспределенияработы
междупотоками:директиваsections
Директиваsections используетсядля заданияконечного (неитеративного) параллелизма.
Директиваsections содержитнабор структурированныхблоков, которые распределяютсяпопотокам вгруппе.
Каждыйструктурированный блок исполняетсяодинразоднимизпотоков в группе.
128
Конструкциираспределенияработы
междупотоками:директиваsections
#pragmaompsectionsопция[[[,] опция]...]
{
#pragmaompsection
структурированный блок
#pragmaompsection
структурированный блок
...
}
129
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
private(список) – задаётсписок переменных,для которых порождается локальная копия вкаждой нити; начальноезначениелокальных копий переменныхизсписканеопределено;
130
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
firstprivate(список)– задаётсписок переменных,для которых порождается локальная копия вкаждой нити; локальные копиипеременных инициализируютсязначениямиэтих переменныхвнити-мастере;
131
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
lastprivate(список)– переменным, перечисленнымвсписке,присваивается результат,полученныйвпоследней секции;
132
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
reduction(оператор:список) – задаёт оператор исписокобщихпеременных; длякаждой переменнойсоздаются локальные копиивкаждой нити;
133
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
nowait– вконцеблокасекций происходитнеявнаябарьерная синхронизацияпараллельно работающихнитей:ихдальнейшее выполнениепроисходиттолько тогда, когда всеонидостигнутданнойточки;
134
Конструкциираспределенияработы
междупотоками:директиваsections
Возможныеопции:
nowait–
есливподобной задержкенет необходимости,опцияnowaitпозволяет нитям,ужедошедшимдоконцасвоих секций,продолжить выполнениебез синхронизациисостальными.
135
Конструкциираспределенияработы
междупотоками:директиваsections
Директиваsectionзадаётучастоккода внутрисекцииsections длявыполнения одной нитью.
#pragmaompsection
136
Конструкциираспределенияработы
междупотоками:директиваsections
Передпервымучасткомкодавблоке sections директиваsectionнеобязательна. Какиеименнонитибудутзадействованы длявыполнениякакой секции,не специфицируется.
137
Конструкциираспределенияработы
междупотоками:директиваsections
Есликоличествонитейбольшеколичества секций,точастьнитейдлявыполнения данногоблокасекцийнебудет задействована.Есликоличествонитей меньшеколичествасекций,тонекоторым (иливсем)нитям достанетсяболееодной секции.
138
Конструкциираспределенияработы
междупотоками:директиваsections
Следующийпримердемонстрирует использованиеопцииlastprivate.
Вданномпримереопцияlastprivate используетсявместесдирективой sections.
139
Конструкциираспределенияработы
междупотоками:директиваsections
Переменнаяnобъявленакакlastprivate переменная.
Тринити,выполняющиесекцииsection, присваиваютсвоейлокальной копии n разныезначения.
140
Конструкциираспределенияработы
междупотоками:директиваsections
Повыходеизобластиsections значениеn изпоследнейсекцииприсваивается локальным копиям вовсехнитях, поэтому всенитинапечатаютчисло3.
Это жезначениесохранится для переменнойn ивпоследовательной области.
141
Конструкциираспределенияработы
междупотоками:директиваsections
#include <stdio.h> #include <omp.h>
intmain(int argc,char*argv[])
{
intn=0;
#pragmaompparallel
{
#pragmaompsectionslastprivate(n)
{
142
Конструкциираспределенияработы
междупотоками:директиваsections
#pragmaompsection
{
n=1;
}
#pragmaompsection
{
n=2;
}
#pragmaompsection
{
n=3;
}
} |
143 |
|
Конструкциираспределенияработы
междупотоками:директиваsections
printf("Значениеnнанити%d:%d\n", omp_get_thread_num(),n);
}
printf("Значениеnвпоследовательной области:%d\n",n);
}
144
Конструкциираспределенияработы
междупотоками:директиваmaster
Директивыmasterвыделяютучастоккода, который будетвыполнентолько нитьюмастером.Остальныенитипросто пропускаютданныйучасток ипродолжают работу соператора, расположенного следомзаним.Неявнойсинхронизации даннаядирективанепредполагает.
145
Конструкциираспределенияработы
междупотоками:директиваmaster
#pragmaompmaster
Раздел(clause) — это необязательный модификатор директивы, влияющий на ее поведение. Списки разделов, поддерживаемые каждой директивой, различаются, а пять директив (master, critical,flush, ordered и atomic) вообще не поддерживают разделы.
146
Конструкциираспределенияработы
междупотоками:директиваmaster
Следующийпримердемонстрирует применениедирективыmaster. Переменнаяn являетсялокальной, тоесть каждая нитьработает сосвоим экземпляром.
147
Конструкциираспределенияработы
междупотоками:директиваmaster
Сначалавсенитиприсвоятпеременнойn значение1.Потом нить-мастерприсвоит переменнойnзначение2,ивсенити напечатаютзначениеn.
148
Конструкциираспределенияработы
междупотоками:директиваmaster
Затем нить-мастерприсвоитпеременнойn значение3,исновавсенитинапечатают значениеn.
149
Конструкциираспределенияработы
междупотоками:директиваmaster
Видно,чтодирективуmasterвсегда выполняетоднаитаженить.Вданном примеревсенитивыведутзначение1,а нить-мастерсначалавыведетзначение2, апотомзначение3.
150
Конструкциираспределенияработы между потоками: директиваmaster
#include <stdio.h>
int main(int argc, char *argv[])
{
int n;
#pragma omp parallel private(n)
{
n = 1;
#pragma omp master
{
n = 2;
}
printf("Первоезначениеn:%d\n",n);
151
Конструкциираспределенияработы
междупотоками:директиваmaster
#pragma omp barrier #pragma omp master
{
n=3;
}
printf("Второе значениеn:%d\n",n);
}
}
152
Конструкциисинхронизации:
директиваcritical
С помощью директив critical оформляется критическая секция программы.
#pragma omp critical имя[()]
структурированный блок
Критическая секция запрещает одновременное исполнение структурированного блока более чем одним потоком.
Конструкциисинхронизации:
директиваcritical
Следующий пример иллюстрирует применение директивы critical. Переменнаяn объявленавне параллельной области, поэтому по умолчанию является общей.Критическая секция позволяет разграничить доступ к переменной n. Каждая нить по очереди присвоит n свой номер и затем напечатает полученное значение.
Конструкциисинхронизации:
директиваcritical
#include <stdio.h> #include <omp.h>
int main(int argc, char *argv[])
{
int n;
#pragma omp parallel
{
#pragma omp critical
{
n = omp_get_thread_num(); printf("Нить %d\n", n);
}
}
}
Конструкциисинхронизации:
директиваbarrier
Самый распространенный способ синхронизации в OpenMP – барьер. Он оформляется с помощью директивы barrier.
#pragma omp barrier
Директива barrier дает всем потокам указание ожидать друг друга перед тем, как они продолжат выполнение за барьером.
Конструкциисинхронизации:
директиваbarrier
Нити, выполняющие текущую параллельную область, дойдя до этой директивы, останавливаютсяи ждут, пока все нити не дойдут до этой точки программы, после чего разблокируются и продолжают работать дальше. Кроме того, для разблокировки необходимо, чтобы все синхронизируемые нити завершили все порождённые ими задачи (task).
Конструкциисинхронизации:
директиваbarrier
Следующий пример демонстрирует применение директивы barrier. Директива barrier используется для упорядочивания вывода от работающих нитей. Выдачи с разных нитей "Сообщение 1"и "Сообщение 2“ могут чередоваться в произвольном порядке, а выдача "Сообщение 3« со всех нитей придёт строго после двух предыдущих выдач.
Конструкциисинхронизации:
директиваbarrier
#include <stdio.h> #include <omp.h>
intmain(intargc,char*argv[])
{
#pragmaompparallel
{
printf("Сообщение1\n"); printf("Сообщение2\n");
#pragmaompbarrier printf("Сообщение3\n");
}
}