Я пытаюсь придумать эквивалентную замену Intel TBB parallel_for
цикл, который использует tbb::blocked_range
используя OpenMP. Покопавшись в Интернете, мне удалось найти упоминание только об одном человеке, делающем нечто подобное; патч, представленный в проект Open Cascade, в котором цикл TBB выглядел так (но не использовал tbb :: block_range):
tbb::parallel_for_each (aFaces.begin(), aFaces.end(), *this);
и эквивалент OpenMP был:
int i, n = aFaces.size();
#pragma omp parallel for private(i)
for (i = 0; i < n; ++i)
Process (aFaces[i]);
Вот цикл TBB, который я пытаюсь заменить:
tbb::parallel_for( tbb::blocked_range<size_t>( 0, targetList.size() ), DoStuff( targetList, data, vec, ptr ) );
Он использует DoStuff
класс для выполнения работы:
class DoStuff
{
private:
List& targetList;
Data* data;
vector<things>& vec;
Worker* ptr;
public:
DoIdentifyTargets( List& pass_targetList,
Data* pass_data,
vector<things>& pass_vec,
Worker* pass_worker)
: targetList(pass_targetList), data(pass_data), vecs(pass_vec), ptr(pass_worker)
{
}
void operator() ( const tbb::blocked_range<size_t> range ) const
{
for ( size_t idx = range.begin(); idx != range.end(); ++idx )
{
ptr->PerformWork(&targetList[idx], data->getData(), &Vec);
}
}
};
Мое понимание на основании этой ссылки в том, что TBB разделит заблокированный диапазон на более мелкие подмножества и даст каждому потоку один из диапазонов для циклического прохождения Так как каждый поток получит свой DoStuff
класс, который имеет кучу ссылок и указателей, что означает, что потоки по существу разделяют эти ресурсы.
Вот что я предложил в качестве эквивалентной замены в OpenMP:
int index = 0;
#pragma omp parallel for private(index)
for (index = 0; index < targetList.size(); ++index)
{
ptr->PerformWork(&targetList[index], data->getData(), &Vec);
}
Из-за не зависящих от меня обстоятельств (это всего лишь один компонент в гораздо более крупной системе, охватывающей +5 компьютеров), выполняющего код с помощью отладчика, чтобы точно увидеть, что происходит … Вряд ли. Я работаю над удаленной отладкой, но она не выглядит многообещающей. Все, что я точно знаю, это то, что вышеприведенный код OpenMP каким-то образом работает не так, как TBB, и ожидаемые результаты после вызова PerformWork для каждого индекса не получаются.
Учитывая приведенную выше информацию, есть ли у кого-нибудь идеи о том, почему коды OpenMP и TBB не являются функционально эквивалентными?
Следуя совету Бена и Рика, я протестировал следующий цикл без прагмы omp (серийно) и получил ожидаемые результаты (очень медленно). После добавления прагмы, параллельный код также работает как ожидалось. Похоже, проблема заключалась либо в объявлении индекса как частного за пределами цикла, либо в объявлении numTargets как частного внутри цикла. Или оба.
int numTargets = targetList.size();
#pragma omp parallel for
for (int index = 0; index < numTargets; ++index)
{
ptr->PerformWork(&targetList[index], data->getData(), &vec);
}
Других решений пока нет …