Я бы просто отделил (начало) параллельной области от цикла и использовал бы приватную переменную, чтобы сохранить 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, это может привести к гонке данных в вашей программе.