Поделиться через


Предложения 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, guidedruntimeлибо 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см. в закрытом режиме.