Как firstprivate и lastprivate отличаются от private clauses в OpenMP?

Я просмотрел официальные определения, но я все еще довольно смущен.

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

Для меня это очень похоже на личное. Я искал примеры, но я, кажется, не понимаю, как это особенное или как его можно использовать.

lastprivate: Указывает, что вложенная версия контекста переменной установлена ​​равной частной версии любого потока, который выполняет окончательную итерацию (for-loop construct) или последний раздел (разделы #pragma).

Мне кажется, я понимаю это немного лучше из-за следующего примера:

#pragma omp parallel
{
   #pragma omp for lastprivate(i)
      for (i=0; i<n-1; i++)
         a[i] = b[i] + b[i+1];
}
a[i]=b[i];

Итак, в этом примере я понимаю, что lastprivate позволяет возвращать i за пределы цикла в качестве последнего значения.

Я только начал изучать OpenMP сегодня.

Ответ 1

private переменные не инициализируются, т.е. они начинаются со случайных значений, как любая другая локальная автоматическая переменная (и они часто реализуются с использованием автоматических переменных в стеке каждого потока). Возьмите эту простую программу в качестве примера:

#include <stdio.h>
#include <omp.h>

int main (void)
{
    int i = 10;

    #pragma omp parallel private(i)
    {
        printf("thread %d: i = %d\n", omp_get_thread_num(), i);
        i = 1000 + omp_get_thread_num();
    }

    printf("i = %d\n", i);

    return 0;
}

С четырьмя потоками он выводит что-то вроде:

thread 0: i = 0
thread 3: i = 32717
thread 1: i = 32717
thread 2: i = 1
i = 10

(another run of the same program)

thread 2: i = 1
thread 1: i = 1
thread 0: i = 0
thread 3: i = 32657
i = 10

Это наглядно демонстрирует, что значение i является случайным (не инициализированным) внутри параллельной области и что любые его модификации не видны после параллельной области (т.е. переменная сохраняет свое значение до входа в область).

Если i сделано firstprivate, то оно инициализируется значением, которое оно имеет перед параллельной областью:

thread 2: i = 10
thread 0: i = 10
thread 3: i = 10
thread 1: i = 10
i = 10

После него все еще изменения значения i внутри параллельной области не видны.

Вы уже знаете о lastprivate (и он не применим к простой демонстрационной программе, поскольку он не имеет конструкций для совместной работы).

Итак, да, firstprivate и lastprivate являются только особыми случаями private. Первый результат приводит к тому, что значения из внешнего контекста приводятся в параллельный регион, а второй переносит значения из параллельной области во внешний контекст. Обоснованием этих классов совместного использования данных является то, что внутри параллельной области все частные переменные затеняют те из внешних контекстов, то есть невозможно использовать операцию присваивания для изменения внешнего значения i изнутри параллельной области.

Ответ 2

firstprivate и lastprivate являются только особыми случаями private.

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