OpenMp: как сделать размерный std :: vector threadprivate - PullRequest
2 голосов
/ 03 июля 2019

Я новичок в мире OpenMp и получил ошибку, которую не могу исправить.Оригинальный код - это большой, поэтому я сделал небольшой код, чтобы подвести итог проблемы:

Я получил более размерный std::vector (2d и 3d), который не должен быть разделен между потоками.Если я отмечу их как частные, они по-прежнему вызывают ошибки памяти, потому что потоки все еще их разделяют.

Я нашел решение этой проблемы: я создал еще 1 измерение для 2-го вектора, чтобы каждый поток могполучить доступ к своей собственной копии:

myVector[omp_get_thread_num()][1].push_back(i);

Я знаю, что это не умное решение для моей проблемы, но теперь каждый поток получил свою собственную копию 2d Vector.Теперь начинается странная часть: это все еще вызывает сбой памяти, иногда, если я не поставлю #pragma omp critial перед ним.Я действительно не понимаю, почему это необходимо, потому что потоки никогда не должны обращаться к одной и той же памяти.

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

//this should represent my problem(without my fix)
int main(){
        std::vector < std::vector < int > > v;
    v.resize(3);

    #pragma omp parallel for num_threads(2) private(v)
    for(int i = 0; i < 10; i++){
            v[1].push_back(i); 
    }
    return 0;
}

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

ps.невозможно выделить вектор внутри части omp.

Ответы [ 3 ]

1 голос
/ 03 июля 2019

Вы должны понимать, что переменные, поступающие из внешней области, которые объявлены private, работают так, как если бы они были локально объявлены без инициализатора . Таким образом, каждая локальная копия является пустым вектором, поэтому ваш код не может работать.

Как правило, с OpenMP лучше объявлять закрытые переменные локально - таким образом вы избежите путаницы между «внешним значением» и «внутренними частными значениями», которые вообще не связаны. Вы можете сделать это, разделив директивы parallel и for.

#pragma omp parallel
{
    std::vector<std::vector<int>> v;
    v.resize(3);
    #pragma omp for
    for(int i = 0; i < 10; i++){
        v[1].push_back(i); 
    }
}

Обратите внимание, что v недоступен после параллельной области - это хорошо! В вашем исходном примере v доступен после параллельной области - но это значение не имеет ничего общего со значением из потоков внутри.

Если вам нужно сохранить информацию из v, вы можете посмотреть на сокращение, но это зависит от вашего конкретного варианта использования.

Ваш подход myVector[omp_get_thread_num()] общий наивный подход. Этот код правильный , но в любом случае, когда вы изменяете значения самого внешнего вектора , он имеет плохую производительность из-за ложного совместного использования.

myVector[omp_get_thread_num()].push_back(); // Bad performance
myVector[omp_get_thread_num()][1].push_back(i); // Ok

Так что, как правило, желательно не делать этого и использовать вместо этого объявленные локально переменные. Тем не менее, если ваш код вылетает, значит что-то не так. В этом случае вам нужно подготовить минимальный воспроизводимый пример и задать второй вопрос (ссылаясь на это).

Теперь threadprivate - это нечто иное, чем private. private обычно является тем, что вы хотите, и относится к конкретной задаче / области. В большинстве случаев вам не нужно или не нужно threadprivate.

0 голосов
/ 03 июля 2019

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

int main() {
   #pramga omp parallel
   {
      std::vector<std::vector<int>> v;
      v.resize(3);

      #pragma omp for 
      for (int i = 0; i < 10; i++)
         v[1].push_back(i); 
   }
}
0 голосов
/ 03 июля 2019

Вы можете использовать спецификатор хранилища thread_local:

int main(){
   thread_local std::vector < std::vector < int > > v;
   // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...