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