Предложения OpenMP
Содержит ссылки на предложения, используемые в API OpenMP.
Visual C++ поддерживает следующие предложения OpenMP.
Для общих атрибутов:
Предложение | Description |
---|---|
if | Указывает, должен ли цикл выполняться параллельно или последовательно. |
num_threads | Задает количество потоков в команде потоков. |
упорядоченный | Требуется для параллельной инструкции, если в цикле будет использоваться упорядоченная директива. |
schedule | Применяется к директиве for . |
nowait | Переопределяет барьер, неявный в директиве. |
Для атрибутов общего доступа к данным:
Предложение | Description |
---|---|
private | Указывает, что каждый поток должен иметь собственный экземпляр переменной. |
firstprivate | Указывает, что каждый поток должен иметь собственный экземпляр переменной, и что переменная должна быть инициализирована со значением переменной, так как она существует до параллельной конструкции. |
lastprivate | Указывает, что версия включающего контекста переменной равна частной версии любого потока, выполняющего окончательную итерацию (конструкцию для цикла) или последний раздел (#pragma разделах). |
совместный | Указывает, что одна или несколько переменных должны быть общими для всех потоков. |
default | Указывает поведение неуправляемых переменных в параллельном регионе. |
reduction | Указывает, что одна или несколько переменных, которые являются частными для каждого потока, являются предметом операции сокращения в конце параллельного региона. |
copyin | Позволяет потокам получить доступ к значению основного потока для переменной threadprivate . |
copyprivate | Указывает, что одна или несколько переменных должны быть общими для всех потоков. |
copyin
Позволяет потокам получить доступ к значению основного потока для переменной threadprivate .
copyin(var)
Параметры
var
Переменная threadprivate
, которая будет инициализирована со значением переменной в основном потоке, так как она существует до параллельной конструкции.
Замечания
copyin
Применяется к следующим директивам:
Дополнительные сведения см. в разделе 2.7.2.7 copyin.
Пример
Пример использования copyin
см. в разделе threadprivate.
copyprivate
Указывает, что одна или несколько переменных должны быть общими для всех потоков.
copyprivate(var)
Параметры
var
Одна или несколько переменных для совместного использования. Если указано несколько переменных, разделите имена переменных запятой.
Замечания
copyprivate
применяется к одной директиве.
Дополнительные сведения см. в разделе 2.7.2.8 copyprivate.
Пример
// omp_copyprivate.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
float x, y, fGlobal = 1.0;
#pragma omp threadprivate(x, y)
float get_float() {
fGlobal += 0.001;
return fGlobal;
}
void use_float(float f, int t) {
printf_s("Value = %f, thread = %d\n", f, t);
}
void CopyPrivate(float a, float b) {
#pragma omp single copyprivate(a, b, x, y)
{
a = get_float();
b = get_float();
x = get_float();
y = get_float();
}
use_float(a, omp_get_thread_num());
use_float(b, omp_get_thread_num());
use_float(x, omp_get_thread_num());
use_float(y, omp_get_thread_num());
}
int main() {
float a = 9.99, b = 123.456;
printf_s("call CopyPrivate from a single thread\n");
CopyPrivate(9.99, 123.456);
printf_s("call CopyPrivate from a parallel region\n");
#pragma omp parallel
{
CopyPrivate(a, b);
}
}
call CopyPrivate from a single thread
Value = 1.001000, thread = 0
Value = 1.002000, thread = 0
Value = 1.003000, thread = 0
Value = 1.004000, thread = 0
call CopyPrivate from a parallel region
Value = 1.005000, thread = 0
Value = 1.005000, thread = 1
Value = 1.006000, thread = 0
Value = 1.006000, thread = 1
Value = 1.007000, thread = 0
Value = 1.007000, thread = 1
Value = 1.008000, thread = 0
Value = 1.008000, thread = 1
default
Указывает поведение неуправляемых переменных в параллельном регионе.
default(shared | none)
Замечания
shared
, который действует, если default
предложение не указано, означает, что любая переменная в параллельном регионе будет рассматриваться как если бы она была указана с общим предложением. none
означает, что любые переменные, используемые в параллельном регионе, которые не ограничены частными, общими, сокращением, первопривычиной или предложением lastprivate, приведет к ошибке компилятора.
default
Применяется к следующим директивам:
Дополнительные сведения см. в разделе 2.7.2.5 по умолчанию.
Пример
Пример использования default
см. в закрытом режиме.
firstprivate
Указывает, что каждый поток должен иметь собственный экземпляр переменной, и что переменная должна быть инициализирована со значением переменной, так как она существует до параллельной конструкции.
firstprivate(var)
Параметры
var
Переменная, которая будет иметь экземпляры в каждом потоке, и которая будет инициализирована со значением переменной, так как она существует до параллельной конструкции. Если указано несколько переменных, разделите имена переменных запятой.
Замечания
firstprivate
Применяется к следующим директивам:
Дополнительные сведения см. в статье 2.7.2.2 firstprivate.
Пример
Пример использования firstprivate
см. в примере в закрытом режиме.
if (OpenMP)
Указывает, должен ли цикл выполняться параллельно или последовательно.
if(expression)
Параметры
выражение
Целочисленное выражение, которое, если оно оценивается как true (ненулевое), приводит к параллельному выполнению кода в параллельном регионе. Если выражение оценивается как false (ноль), параллельный регион выполняется последовательно (одним потоком).
Замечания
if
Применяется к следующим директивам:
Дополнительные сведения см . в параллельной конструкции 2.3.
Пример
// omp_if.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
void test(int val)
{
#pragma omp parallel if (val)
if (omp_in_parallel())
{
#pragma omp single
printf_s("val = %d, parallelized with %d threads\n",
val, omp_get_num_threads());
}
else
{
printf_s("val = %d, serialized\n", val);
}
}
int main( )
{
omp_set_num_threads(2);
test(0);
test(2);
}
val = 0, serialized
val = 2, parallelized with 2 threads
lastprivate
Указывает, что версия включающего контекста переменной равна частной версии любого потока, выполняющего окончательную итерацию (конструкцию для цикла) или последний раздел (#pragma разделах).
lastprivate(var)
Параметры
var
Переменная, которая равна частной версии любого потока, выполняет окончательную итерацию (конструкцию для цикла) или последний раздел (#pragma разделы).
Замечания
lastprivate
Применяется к следующим директивам:
Дополнительные сведения см. в разделе 2.7.2.3 lastprivate.
Пример
См . расписание для примера предложения using lastprivate
.
nowait
Переопределяет барьер, неявный в директиве.
nowait
Замечания
nowait
Применяется к следующим директивам:
Дополнительные сведения см. в статье 2.4.1 для конструкции, конструкции разделов 2.4.2 и 2.4.3.
Пример
// omp_nowait.cpp
// compile with: /openmp /c
#include <stdio.h>
#define SIZE 5
void test(int *a, int *b, int *c, int size)
{
int i;
#pragma omp parallel
{
#pragma omp for nowait
for (i = 0; i < size; i++)
b[i] = a[i] * a[i];
#pragma omp for nowait
for (i = 0; i < size; i++)
c[i] = a[i]/2;
}
}
int main( )
{
int a[SIZE], b[SIZE], c[SIZE];
int i;
for (i=0; i<SIZE; i++)
a[i] = i;
test(a,b,c, SIZE);
for (i=0; i<SIZE; i++)
printf_s("%d, %d, %d\n", a[i], b[i], c[i]);
}
0, 0, 0
1, 1, 0
2, 4, 1
3, 9, 1
4, 16, 2
num_threads
Задает количество потоков в команде потоков.
num_threads(num)
Параметры
num
Количество потоков
Замечания
Предложение num_threads
имеет ту же функциональность, что и функция omp_set_num_threads .
num_threads
Применяется к следующим директивам:
Дополнительные сведения см . в параллельной конструкции 2.3.
Пример
Пример использования предложения см. параллельно.num_threads
упорядоченного
Требуется для параллельной инструкции, если в цикле будет использоваться упорядоченная директива.
ordered
Замечания
ordered
применяется к директиве for .
Дополнительные сведения см. в статье 2.4.1 для конструкции.
Пример
См . упорядоченный пример предложения using ordered
.
private
Указывает, что каждый поток должен иметь собственный экземпляр переменной.
private(var)
Параметры
var
Переменная для каждого потока имеет экземпляры.
Замечания
private
Применяется к следующим директивам:
Дополнительные сведения см . в закрытом режиме 2.7.2.1.
Пример
// openmp_private.c
// compile with: /openmp
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define SLEEP_THREAD 1
#define NUM_LOOPS 2
enum Types {
ThreadPrivate,
Private,
FirstPrivate,
LastPrivate,
Shared,
MAX_TYPES
};
int nSave[NUM_THREADS][MAX_TYPES][NUM_LOOPS] = {{0}};
int nThreadPrivate;
#pragma omp threadprivate(nThreadPrivate)
#pragma warning(disable:4700)
int main() {
int nPrivate = NUM_THREADS;
int nFirstPrivate = NUM_THREADS;
int nLastPrivate = NUM_THREADS;
int nShared = NUM_THREADS;
int nRet = 0;
int i;
int j;
int nLoop = 0;
nThreadPrivate = NUM_THREADS;
printf_s("These are the variables before entry "
"into the parallel region.\n");
printf_s("nThreadPrivate = %d\n", nThreadPrivate);
printf_s(" nPrivate = %d\n", nPrivate);
printf_s(" nFirstPrivate = %d\n", nFirstPrivate);
printf_s(" nLastPrivate = %d\n", nLastPrivate);
printf_s(" nShared = %d\n\n", nShared);
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel copyin(nThreadPrivate) private(nPrivate) shared(nShared) firstprivate(nFirstPrivate)
{
#pragma omp for schedule(static) lastprivate(nLastPrivate)
for (i = 0 ; i < NUM_THREADS ; ++i) {
for (j = 0 ; j < NUM_LOOPS ; ++j) {
int nThread = omp_get_thread_num();
assert(nThread < NUM_THREADS);
if (nThread == SLEEP_THREAD)
Sleep(100);
nSave[nThread][ThreadPrivate][j] = nThreadPrivate;
nSave[nThread][Private][j] = nPrivate;
nSave[nThread][Shared][j] = nShared;
nSave[nThread][FirstPrivate][j] = nFirstPrivate;
nSave[nThread][LastPrivate][j] = nLastPrivate;
nThreadPrivate = nThread;
nPrivate = nThread;
nShared = nThread;
nLastPrivate = nThread;
--nFirstPrivate;
}
}
}
for (i = 0 ; i < NUM_LOOPS ; ++i) {
for (j = 0 ; j < NUM_THREADS ; ++j) {
printf_s("These are the variables at entry of "
"loop %d of thread %d.\n", i + 1, j);
printf_s("nThreadPrivate = %d\n",
nSave[j][ThreadPrivate][i]);
printf_s(" nPrivate = %d\n",
nSave[j][Private][i]);
printf_s(" nFirstPrivate = %d\n",
nSave[j][FirstPrivate][i]);
printf_s(" nLastPrivate = %d\n",
nSave[j][LastPrivate][i]);
printf_s(" nShared = %d\n\n",
nSave[j][Shared][i]);
}
}
printf_s("These are the variables after exit from "
"the parallel region.\n");
printf_s("nThreadPrivate = %d (The last value in the "
"main thread)\n", nThreadPrivate);
printf_s(" nPrivate = %d (The value prior to "
"entering parallel region)\n", nPrivate);
printf_s(" nFirstPrivate = %d (The value prior to "
"entering parallel region)\n", nFirstPrivate);
printf_s(" nLastPrivate = %d (The value from the "
"last iteration of the loop)\n", nLastPrivate);
printf_s(" nShared = %d (The value assigned, "
"from the delayed thread, %d)\n\n",
nShared, SLEEP_THREAD);
}
These are the variables before entry into the parallel region.
nThreadPrivate = 4
nPrivate = 4
nFirstPrivate = 4
nLastPrivate = 4
nShared = 4
These are the variables at entry of loop 1 of thread 0.
nThreadPrivate = 4
nPrivate = 1310720
nFirstPrivate = 4
nLastPrivate = 1245104
nShared = 3
These are the variables at entry of loop 1 of thread 1.
nThreadPrivate = 4
nPrivate = 4488
nFirstPrivate = 4
nLastPrivate = 19748
nShared = 0
These are the variables at entry of loop 1 of thread 2.
nThreadPrivate = 4
nPrivate = -132514848
nFirstPrivate = 4
nLastPrivate = -513199792
nShared = 4
These are the variables at entry of loop 1 of thread 3.
nThreadPrivate = 4
nPrivate = 1206
nFirstPrivate = 4
nLastPrivate = 1204
nShared = 2
These are the variables at entry of loop 2 of thread 0.
nThreadPrivate = 0
nPrivate = 0
nFirstPrivate = 3
nLastPrivate = 0
nShared = 0
These are the variables at entry of loop 2 of thread 1.
nThreadPrivate = 1
nPrivate = 1
nFirstPrivate = 3
nLastPrivate = 1
nShared = 1
These are the variables at entry of loop 2 of thread 2.
nThreadPrivate = 2
nPrivate = 2
nFirstPrivate = 3
nLastPrivate = 2
nShared = 2
These are the variables at entry of loop 2 of thread 3.
nThreadPrivate = 3
nPrivate = 3
nFirstPrivate = 3
nLastPrivate = 3
nShared = 3
These are the variables after exit from the parallel region.
nThreadPrivate = 0 (The last value in the main thread)
nPrivate = 4 (The value prior to entering parallel region)
nFirstPrivate = 4 (The value prior to entering parallel region)
nLastPrivate = 3 (The value from the last iteration of the loop)
nShared = 1 (The value assigned, from the delayed thread, 1)
поверхности атаки
Указывает, что одна или несколько переменных, которые являются частными для каждого потока, являются предметом операции сокращения в конце параллельного региона.
reduction(operation:var)
Параметры
operation
Оператор операции, выполняемый в переменной переменных в конце параллельного региона.
var
Одна или несколько переменных, для которых выполняется скалярное сокращение. Если указано несколько переменных, разделите имена переменных запятой.
Замечания
reduction
Применяется к следующим директивам:
Дополнительные сведения см. в разделе 2.7.2.6.
Пример
// omp_reduction.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define SUM_START 1
#define SUM_END 10
#define FUNC_RETS {1, 1, 1, 1, 1}
int bRets[5] = FUNC_RETS;
int nSumCalc = ((SUM_START + SUM_END) * (SUM_END - SUM_START + 1)) / 2;
int func1( ) {return bRets[0];}
int func2( ) {return bRets[1];}
int func3( ) {return bRets[2];}
int func4( ) {return bRets[3];}
int func5( ) {return bRets[4];}
int main( )
{
int nRet = 0,
nCount = 0,
nSum = 0,
i,
bSucceed = 1;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel reduction(+ : nCount)
{
nCount += 1;
#pragma omp for reduction(+ : nSum)
for (i = SUM_START ; i <= SUM_END ; ++i)
nSum += i;
#pragma omp sections reduction(&& : bSucceed)
{
#pragma omp section
{
bSucceed = bSucceed && func1( );
}
#pragma omp section
{
bSucceed = bSucceed && func2( );
}
#pragma omp section
{
bSucceed = bSucceed && func3( );
}
#pragma omp section
{
bSucceed = bSucceed && func4( );
}
#pragma omp section
{
bSucceed = bSucceed && func5( );
}
}
}
printf_s("The parallel section was executed %d times "
"in parallel.\n", nCount);
printf_s("The sum of the consecutive integers from "
"%d to %d, is %d\n", 1, 10, nSum);
if (bSucceed)
printf_s("All of the functions, func1 through "
"func5 succeeded!\n");
else
printf_s("One or more of the functions, func1 "
"through func5 failed!\n");
if (nCount != NUM_THREADS)
{
printf_s("ERROR: For %d threads, %d were counted!\n",
NUM_THREADS, nCount);
nRet |= 0x1;
}
if (nSum != nSumCalc)
{
printf_s("ERROR: The sum of %d through %d should be %d, "
"but %d was reported!\n",
SUM_START, SUM_END, nSumCalc, nSum);
nRet |= 0x10;
}
if (bSucceed != (bRets[0] && bRets[1] &&
bRets[2] && bRets[3] && bRets[4]))
{
printf_s("ERROR: The sum of %d through %d should be %d, "
"but %d was reported!\n",
SUM_START, SUM_END, nSumCalc, nSum);
nRet |= 0x100;
}
}
The parallel section was executed 4 times in parallel.
The sum of the consecutive integers from 1 to 10, is 55
All of the functions, func1 through func5 succeeded!
планирование
Применяется к директиве for .
schedule(type[,size])
Параметры
type
Тип планирования либо dynamic
, guided
runtime
либо static
.
size
(Необязательно) Задает размер итерации. размер должен быть целым числом. Недопустимо, если тип имеет значение runtime
.
Замечания
Дополнительные сведения см. в статье 2.4.1 для конструкции.
Пример
// omp_schedule.cpp
// compile with: /openmp
#include <windows.h>
#include <stdio.h>
#include <omp.h>
#define NUM_THREADS 4
#define STATIC_CHUNK 5
#define DYNAMIC_CHUNK 5
#define NUM_LOOPS 20
#define SLEEP_EVERY_N 3
int main( )
{
int nStatic1[NUM_LOOPS],
nStaticN[NUM_LOOPS];
int nDynamic1[NUM_LOOPS],
nDynamicN[NUM_LOOPS];
int nGuided[NUM_LOOPS];
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel
{
#pragma omp for schedule(static, 1)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nStatic1[i] = omp_get_thread_num( );
}
#pragma omp for schedule(static, STATIC_CHUNK)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nStaticN[i] = omp_get_thread_num( );
}
#pragma omp for schedule(dynamic, 1)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nDynamic1[i] = omp_get_thread_num( );
}
#pragma omp for schedule(dynamic, DYNAMIC_CHUNK)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nDynamicN[i] = omp_get_thread_num( );
}
#pragma omp for schedule(guided)
for (int i = 0 ; i < NUM_LOOPS ; ++i)
{
if ((i % SLEEP_EVERY_N) == 0)
Sleep(0);
nGuided[i] = omp_get_thread_num( );
}
}
printf_s("------------------------------------------------\n");
printf_s("| static | static | dynamic | dynamic | guided |\n");
printf_s("| 1 | %d | 1 | %d | |\n",
STATIC_CHUNK, DYNAMIC_CHUNK);
printf_s("------------------------------------------------\n");
for (int i=0; i<NUM_LOOPS; ++i)
{
printf_s("| %d | %d | %d | %d |"
" %d |\n",
nStatic1[i], nStaticN[i],
nDynamic1[i], nDynamicN[i], nGuided[i]);
}
printf_s("------------------------------------------------\n");
}
------------------------------------------------
| static | static | dynamic | dynamic | guided |
| 1 | 5 | 1 | 5 | |
------------------------------------------------
| 0 | 0 | 0 | 2 | 1 |
| 1 | 0 | 3 | 2 | 1 |
| 2 | 0 | 3 | 2 | 1 |
| 3 | 0 | 3 | 2 | 1 |
| 0 | 0 | 2 | 2 | 1 |
| 1 | 1 | 2 | 3 | 3 |
| 2 | 1 | 2 | 3 | 3 |
| 3 | 1 | 0 | 3 | 3 |
| 0 | 1 | 0 | 3 | 3 |
| 1 | 1 | 0 | 3 | 2 |
| 2 | 2 | 1 | 0 | 2 |
| 3 | 2 | 1 | 0 | 2 |
| 0 | 2 | 1 | 0 | 3 |
| 1 | 2 | 2 | 0 | 3 |
| 2 | 2 | 2 | 0 | 0 |
| 3 | 3 | 2 | 1 | 0 |
| 0 | 3 | 3 | 1 | 1 |
| 1 | 3 | 3 | 1 | 1 |
| 2 | 3 | 3 | 1 | 1 |
| 3 | 3 | 0 | 1 | 3 |
------------------------------------------------
общая
Указывает, что одна или несколько переменных должны быть общими для всех потоков.
shared(var)
Параметры
var
Одна или несколько переменных для совместного использования. Если указано несколько переменных, разделите имена переменных запятой.
Замечания
Другим способом совместного использования переменных между потоками является предложение copyprivate .
shared
Применяется к следующим директивам:
Дополнительные сведения см. в разделе 2.7.2.4.
Пример
Пример использования shared
см. в закрытом режиме.