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


Директивы OpenMP

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

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

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

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

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

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

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

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

atomic

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

#pragma omp atomic
   expression

Параметры

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

Замечания

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

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

Пример

// 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

Замечания

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

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

Пример

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

критический

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

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

Параметры

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

Замечания

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

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

Пример

// 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)]

Параметры

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

Замечания

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

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

Пример

// 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 внутри параллельного региона будет разделена между потоками.

#pragma omp [parallel] for [clauses]
   for_statement

Параметры

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

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

Замечания

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

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

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

Пример

// 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
}

Замечания

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

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

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

Пример

// 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

упорядоченного

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

#pragma omp ordered
   structured-block

Замечания

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

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

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

Пример

// 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
}

Параметры

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

Замечания

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

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

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

Пример

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

// 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

разделы

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

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

Параметры

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

Замечания

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

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

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

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

Пример

// 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

отдельный

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

#pragma omp single [clauses]
{
   code_block
}

Параметры

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

Замечания

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

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

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

Пример

// 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)

Параметры

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

Замечания

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

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

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

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

struct MyType
{
    ~MyType();
};

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

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

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

Пример

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