OpenMP параллельно для не POD - PullRequest
0 голосов
/ 09 июня 2011

Я пытаюсь ускорить программу, в основе которой лежит тривиально выглядящий цикл:

double sum=0.;
#pragma omp parallel for reduction(+:sum) // fails
for( size_t i=0; i<_S.size(); ++i ){
  sum += _S[i].first* R(atoms,_S[i].second) ;
}

Хотя сам цикл тривиален, объекты внутри него не являются POD: Здесь_S на самом деле std::vector< std::pair<double, std::vector<size_t> > >, а R(...) - перегруженный operator(...) const какого-либо объекта.Оба его аргумента квалифицированы как const, так что вызов не имеет побочных эффектов.

Поскольку около 90% времени выполнения тратится на этот вызов, казалось, что просто добавить прагму OpenMP, как показано выше, и получить ускорение в два-три раза;но конечно --- код работает нормально с одним потоком, но дает явно неправильные результаты для более чем одного потока :-).

Зависимости данных нет, как _S, так и R(...) кажется безопасным для совместного использования между потоками, но все же это приводит к бессмысленности.

Буду очень признателен за любые указания, как найти, что идет не так.

UPD2:

Разобрался.Как и все ошибки, это тривиально.R(...) вызывал operator() чего-то подобного:

class objR{
 public:
   objR(const size_t N){
     _buffer.reserve(N);
   };
   double operator(...) const{
     // do something, using the _buffer to store intermediaries
   }

 private:
   std::vector<double> _buffer;
};

Очевидно, что разные потоки используют _buffer одновременно и портят его.Мое решение до сих пор состоит в том, чтобы выделить больше места (память не является проблемой, код привязан к процессору):

class objR{
 public:
   objR(const size_t N){
     int nth=1;
     #ifdef _OPENMP
       nth=omp_get_max_threads();
     #endif
     _buffer.resize(N);
   }

   double operator(...) const{
     int thread_id=0;
     #ifdef _OPENMP
       thread_id = omp_get_thread_num();
     #endif
     // do something, using the _buffer[thread_id] to store intermediaries
   }

 private:
   std::vector< std::vector<double> > _buffer;
};

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

1 Ответ

1 голос
/ 09 июня 2011

Доступ к _S[i].first и _S[i].second совершенно безопасен (ничего не может гарантировать о atoms).Это означает, что ваш вызов функции R должен быть причиной проблемы.Вам необходимо выяснить, что такое R, и опубликовать, что он делает.

В другом месте имена, которые начинаются со знака подчеркивания и начинаются с символа в верхнем регистре, зарезервированы для реализации, и вы вызываете неопределенное поведение, используяих.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...