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


OpenMP Directives

Предоставляет ссылки на директивы, используемые в API OpenMP.

Visual C++ поддерживает следующие директивы OpenMP.

Для параллельного совместного использования рабочих операций:

Directive Description
parallel Определяет параллельный регион, который является кодом, который будет выполняться несколькими потоками параллельно.
for Приводит к тому, что работа в цикле for внутри параллельного региона будет разделена между потоками.
sections Определяет разделы кода, которые необходимо разделить между всеми потоками.
single Позволяет указать, что раздел кода должен выполняться в одном потоке, а не в основном потоке.

Для основного потока и синхронизации:

Directive Description
master Указывает, что только основной поток должен выполнять раздел программы.
critical Указывает, что код выполняется только в одном потоке одновременно.
barrier Синхронизирует все потоки в команде; все потоки приостанавливают на барьере, пока все потоки не выполняют барьер.
atomic Указывает, что расположение памяти будет обновляться атомарным образом.
flush Указывает, что все потоки имеют одинаковое представление памяти для всех общих объектов.
ordered Указывает, что код под параллелизованным for циклом должен выполняться как последовательный цикл.

Для среды данных:

Directive Description
threadprivate Указывает, что переменная является частной для потока.

atomic

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

#pragma omp atomic
   expression

Parameters

expression
Оператор, имеющий lvalue, расположение памяти которого требуется защитить от нескольких операций записи.

Remarks

Директива atomic не поддерживает предложения.

Дополнительные сведения см . в атомарной конструкции 2.6.4.

Example

// omp_atomic.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

#define MAX 10

int main() {
   int count = 0;
   #pragma omp parallel num_threads(MAX)
   {
      #pragma omp atomic
      count++;
   }
   printf_s("Number of threads: %d\n", count);
}
Number of threads: 10

barrier

Синхронизирует все потоки в команде; все потоки приостанавливают на барьере, пока все потоки не выполняют барьер.

#pragma omp barrier

Remarks

Директива barrier не поддерживает предложения.

Дополнительные сведения см . в директиве барьера 2.6.3.

Example

Пример использования barrierсм. в разделе master.

critical

Указывает, что код выполняется только в одном потоке одновременно.

#pragma omp critical [(name)]
{
   code_block
}

Parameters

name
(Необязательно) Имя для идентификации критического кода. Имя должно быть заключено в скобки.

Remarks

Директива critical не поддерживает предложения.

Дополнительные сведения см . в критической конструкции 2.6.2.

Example

// omp_critical.cpp
// compile with: /openmp
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

#define SIZE 10

int main()
{
    int i;
    int max;
    int a[SIZE];

    for (i = 0; i < SIZE; i++)
    {
        a[i] = rand();
        printf_s("%d\n", a[i]);
    }

    max = a[0];
    #pragma omp parallel for num_threads(4)
        for (i = 1; i < SIZE; i++)
        {
            if (a[i] > max)
            {
                #pragma omp critical
                {
                    // compare a[i] and max again because max
                    // could have been changed by another thread after
                    // the comparison outside the critical section
                    if (a[i] > max)
                        max = a[i];
                }
            }
        }

    printf_s("max = %d\n", max);
}
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
max = 29358

flush

Указывает, что все потоки имеют одинаковое представление памяти для всех общих объектов.

#pragma omp flush [(var)]

Parameters

var
(Необязательно) Разделенный запятыми список переменных, представляющих объекты, которые необходимо синхронизировать. Если var не указан, все память сбрасывается.

Remarks

Директива flush не поддерживает предложения.

Дополнительные сведения см . в директиве очистки 2.6.5.

Example

// omp_flush.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

void read(int *data) {
   printf_s("read data\n");
   *data = 1;
}

void process(int *data) {
   printf_s("process data\n");
   (*data)++;
}

int main() {
   int data;
   int flag;

   flag = 0;

   #pragma omp parallel sections num_threads(2)
   {
      #pragma omp section
      {
         printf_s("Thread %d: ", omp_get_thread_num( ));
         read(&data);
         #pragma omp flush(data)
         flag = 1;
         #pragma omp flush(flag)
         // Do more work.
      }

      #pragma omp section
      {
         while (!flag) {
            #pragma omp flush(flag)
         }
         #pragma omp flush(data)

         printf_s("Thread %d: ", omp_get_thread_num( ));
         process(&data);
         printf_s("data = %d\n", data);
      }
   }
}
Thread 0: read data
Thread 1: process data
data = 2

for

Приводит к тому, что работа в цикле for внутри параллельного региона будет разделена между потоками.

#pragma omp [parallel] for [clauses]
   for_statement

Parameters

clauses
(Необязательно) Ноль или более предложений см. в разделе "Примечания".

for_statement
for Цикл. Неопределенное поведение приведет к тому, что код пользователя в цикле for изменяет переменную индекса.

Remarks

Директива for поддерживает следующие предложения:

Если parallel он также указан, может быть любым предложением, clauses принятым parallel директивами или for за исключением nowait.

Дополнительные сведения см. в статье 2.4.1 для конструкции.

Example

// omp_for.cpp
// compile with: /openmp
#include <stdio.h>
#include <math.h>
#include <omp.h>

#define NUM_THREADS 4
#define NUM_START 1
#define NUM_END 10

int main() {
   int i, nRet = 0, nSum = 0, nStart = NUM_START, nEnd = NUM_END;
   int nThreads = 0, nTmp = nStart + nEnd;
   unsigned uTmp = (unsigned((abs(nStart - nEnd) + 1)) *
                               unsigned(abs(nTmp))) / 2;
   int nSumCalc = uTmp;

   if (nTmp < 0)
      nSumCalc = -nSumCalc;

   omp_set_num_threads(NUM_THREADS);

   #pragma omp parallel default(none) private(i) shared(nSum, nThreads, nStart, nEnd)
   {
      #pragma omp master
      nThreads = omp_get_num_threads();

      #pragma omp for
      for (i=nStart; i<=nEnd; ++i) {
            #pragma omp atomic
            nSum += i;
      }
   }

   if  (nThreads == NUM_THREADS) {
      printf_s("%d OpenMP threads were used.\n", NUM_THREADS);
      nRet = 0;
   }
   else {
      printf_s("Expected %d OpenMP threads, but %d were used.\n",
               NUM_THREADS, nThreads);
      nRet = 1;
   }

   if (nSum != nSumCalc) {
      printf_s("The sum of %d through %d should be %d, "
               "but %d was reported!\n",
               NUM_START, NUM_END, nSumCalc, nSum);
      nRet = 1;
   }
   else
      printf_s("The sum of %d through %d is %d\n",
               NUM_START, NUM_END, nSum);
}
4 OpenMP threads were used.
The sum of 1 through 10 is 55

master

Указывает, что только основной поток должен выполнять раздел программы.

#pragma omp master
{
   code_block
}

Remarks

Директива master не поддерживает предложения.

Дополнительные сведения см . в главной конструкции 2.6.1.

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

Example

// compile with: /openmp
#include <omp.h>
#include <stdio.h>

int main( )
{
    int a[5], i;

    #pragma omp parallel
    {
        // Perform some computation.
        #pragma omp for
        for (i = 0; i < 5; i++)
            a[i] = i * i;

        // Print intermediate results.
        #pragma omp master
            for (i = 0; i < 5; i++)
                printf_s("a[%d] = %d\n", i, a[i]);

        // Wait.
        #pragma omp barrier

        // Continue with the computation.
        #pragma omp for
        for (i = 0; i < 5; i++)
            a[i] += i;
    }
}
a[0] = 0
a[1] = 1
a[2] = 4
a[3] = 9
a[4] = 16

ordered

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

#pragma omp ordered
   structured-block

Remarks

Директива ordered должна находиться в динамической степени для или parallel for конструкции с предложением ordered .

Директива ordered не поддерживает предложения.

Дополнительные сведения см. в упорядоченной конструкции 2.6.6.

Example

// omp_ordered.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

static float a[1000], b[1000], c[1000];

void test(int first, int last)
{
    #pragma omp for schedule(static) ordered
    for (int i = first; i <= last; ++i) {
        // Do something here.
        if (i % 2)
        {
            #pragma omp ordered
            printf_s("test() iteration %d\n", i);
        }
    }
}

void test2(int iter)
{
    #pragma omp ordered
    printf_s("test2() iteration %d\n", iter);
}

int main( )
{
    int i;
    #pragma omp parallel
    {
        test(1, 8);
        #pragma omp for ordered
        for (i = 0 ; i < 5 ; i++)
            test2(i);
    }
}
test() iteration 1
test() iteration 3
test() iteration 5
test() iteration 7
test2() iteration 0
test2() iteration 1
test2() iteration 2
test2() iteration 3
test2() iteration 4

parallel

Определяет параллельный регион, который является кодом, который будет выполняться несколькими потоками параллельно.

#pragma omp parallel [clauses]
{
   code_block
}

Parameters

clauses
(Необязательно) Ноль или более предложений см. в разделе "Примечания".

Remarks

Директива parallel поддерживает следующие предложения:

parallel также можно использовать с директивами for и sections .

Дополнительные сведения см . в параллельной конструкции 2.3.

Example

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

// omp_parallel.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}
Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

sections

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

#pragma omp [parallel] sections [clauses]
{
   #pragma omp section
   {
      code_block
   }
}

Parameters

clauses
(Необязательно) Ноль или более предложений см. в разделе "Примечания".

Remarks

Директива sections может содержать ноль или более section директив.

Директива sections поддерживает следующие предложения:

Если parallel он также указан, может быть любым предложением, clauses принятым parallel директивами или sections за исключением nowait.

Дополнительные сведения см. в разделах 2.4.2.

Example

// omp_sections.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
    #pragma omp parallel sections num_threads(4)
    {
        printf_s("Hello from thread %d\n", omp_get_thread_num());
        #pragma omp section
        printf_s("Hello from thread %d\n", omp_get_thread_num());
    }
}
Hello from thread 0
Hello from thread 0

single

Позволяет указать, что раздел кода должен выполняться в одном потоке, а не в основном потоке.

#pragma omp single [clauses]
{
   code_block
}

Parameters

clauses
(Необязательно) Ноль или более предложений см. в разделе "Примечания".

Remarks

Директива single поддерживает следующие предложения:

Дополнительные сведения см . в одной конструкции 2.4.3.

Чтобы указать, что раздел кода должен выполняться только в основном потоке, используйте вместо этого главную директиву.

Example

// omp_single.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
   #pragma omp parallel num_threads(2)
   {
      #pragma omp single
      // Only a single thread can read the input.
      printf_s("read input\n");

      // Multiple threads in the team compute the results.
      printf_s("compute results\n");

      #pragma omp single
      // Only a single thread can write the output.
      printf_s("write output\n");
    }
}
read input
compute results
compute results
write output

threadprivate

Указывает, что переменная является частной для потока.

#pragma omp threadprivate(var)

Parameters

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

Remarks

Директива threadprivate не поддерживает предложения.

Директива threadprivate основана на атрибуте потока с помощью ключевого слова __declspec ; ограничения для __declspec(thread) применения threadprivate. Например, threadprivate переменная будет существовать в любом потоке, запущенном в процессе, а не только в тех потоках, которые являются частью команды потоков, созданной параллельной областью. Помните об этой реализации. Вы можете заметить, что конструкторы для определяемого threadprivate пользователем типа вызываются чаще, чем ожидалось.

Вы можете использовать threadprivate библиотеку DLL, которая статически загружена при запуске процесса, однако вы не можете использовать threadprivate в любой библиотеке DLL, которая будет загружена через LoadLibrary , например библиотеки DLL, загруженные с помощью /DELAYLOAD (задержка импорта нагрузки), который также использует LoadLibrary.

threadprivate Переменная деструкторного типа не гарантирует вызова деструктора. For example:

struct MyType
{
    ~MyType();
};

MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
    #pragma omp parallel
    {}
}

Пользователи не имеют контроля за тем, когда потоки, составляющие параллельный регион, завершаются. Если эти потоки существуют, когда процесс завершается, потоки не будут получать уведомления о выходе процесса, а деструктор не будет вызываться threaded_var в любом потоке, кроме того, который завершается (здесь основной поток). Поэтому код не должен рассчитывать на надлежащее уничтожение threadprivate переменных.

Дополнительные сведения см . в директиве threadprivate 2.7.1.

Example

Пример использования threadprivateсм . в разделе "Частный".