Вызовы OpenMP и директивы, разрешенные в конструкции переменной firstprivate? - PullRequest
0 голосов
/ 17 сентября 2011

У меня есть следующий код, который работает на имеющихся у меня компиляторах (xlC и gcc), но я не знаю, является ли он полностью совместимым (я не нашел в спецификации OpenMP 3.0 ничего, что явно запрещало бы это):

#include <iostream>
#include <vector>
#include <omp.h>

struct A {
  int tid;
  A() : tid(-1) { }
  A(const A&) { tid = omp_get_thread_num(); }
};

int main() {
  A a;

  std::vector<int> v(10);
  std::vector<int>::iterator it;
#pragma omp parallel for firstprivate(a)
  for (it=v.begin(); it<v.end(); ++it)
    *it += a.tid;

  for (it=v.begin(); it<v.end(); ++it)
    std::cout << *it << ' ';
  std::cout << std::endl;
  return 0;
}

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

Ответы [ 2 ]

2 голосов
/ 23 сентября 2011

Я бы просто отделил (начало) параллельной области от цикла и использовал бы приватную переменную, чтобы сохранить tid:

std::vector<int>::iterator it;
int tid;
#pragma omp parallel private(tid)
{
    tid = omp_get_thread_num();
    #pragma omp for 
    for (it=v.begin(); it<v.end(); ++it)
        *it += tid; 
}

Добавлено: ниже приведены цитаты из спецификации OpenMP (Раздел 2.9.3.4), которые заставляют меня думать , что ваш код соответствует и поэтому не выдает UB (однако см. Другое дополнение ниже):

... новый элемент списка инициализируется из исходного элемента списка, существовавшего до создания. Инициализация нового элемента списка выполняется один раз для каждой задачи, которая ссылается на элемент списка в любом операторе в конструкции. Инициализация выполняется до выполнения конструкции.

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

C / C ++: ... Для переменных типа класса вызывается конструктор копирования для выполнения инициализации. Порядок, в котором вызываются конструкторы копирования для различных переменных типа класса, не указан.

C / C ++: переменная типа класса (или ее массив), которая появляется в предложении firstprivate требуется доступный однозначный конструктор копирования для типа класса.

Added-2: Однако не указано, какой поток выполняет конструктор копирования для переменной firstprivate. Теоретически, это может быть сделано главным потоком региона для всех копий переменной. В этом случае значение omp_get_thread_num() будет равно во всех копиях либо 0, либо, в случае вложенных параллельных областей, номер потока во внешней области. Таким образом, будучи определенным поведением с точки зрения OpenMP, это может привести к гонке данных в вашей программе.

0 голосов
/ 17 сентября 2011

Когда вы перебираете вектор, вы должны его использовать!Однако в этом случае ваш параллельный цикл for больше не действителен.Я бы перестроил этот раздел кода следующим образом:

  #pragma omp parallel for firstprivate(a)
  for (int i = 0 ; i < v.size() ; i++ )
     v[i] += a.tid;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...