У меня есть следующий код для перебора std::tuple
, Код отсюда Вот.
#include <tuple>
#include <utility>
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT& f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
Теперь я хотел бы выполнить это for_each
цикл с openmp, так же, как я могу использовать openmp на for
, Есть ли хитрость, чтобы сделать это возможным?
Примечание. Вы можете изменить приведенный выше код или использовать любую другую собственную версию. for_each
,
Синтаксис шаблона C ++ 11 мне очень чужд, но рекурсивные проблемы, подобные этой, лучше всего делать параллельными, используя явные задачи OpenMP:
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT& f)
{
#pragma omp task firstprivate(I) shared(t,f)
{
f(std::get<I>(t));
}
for_each<I + 1, FuncT, Tp...>(t, f);
}
...
// Proper usage
#pragma omp parallel
{
#pragma omp single
for_each(...);
}
Важная часть состоит в том, чтобы иметь вызов на высшем уровне for_each
в single
построить внутри parallel
область, край. Таким образом, только один поток будет вызывать for_each
что в свою очередь приведет к f(std::get<I>(t));
ставится в очередь для последующего выполнения в качестве явной задачи. Другие потоки, ожидая неявного барьера в конце single
конструировать, начнет извлекать задачи из очереди задач и выполнять их параллельно, пока очередь не станет пустой. Классы совместного использования всех переменных, используемых задачей, даны явно для ясности.
Объекты, которые t
а также f
ссылка должна быть общей, а сами ссылки (в основном, указатели, которые реализуют ссылки) должны быть первыми. С другой стороны, стандарт OpenMP запрещает ссылочные типы быть частными, и разные поставщики компиляторов имеют тенденцию реализовывать стандарт по-разному. Компилятор Intel C ++ принимает следующий код и дает правильные результаты внутри задачи, но указанная переменная приватизирована (что неверно):
void f(int& p)
{
#pragma omp task
{
cout << "p = " << p << endl;
p = 3;
cout << "p' = " << p << endl;
}
}
void f1()
{
int i = 5;
#pragma omp parallel
{
#pragma omp single
f(i);
}
cout << "i = " << i << endl;
}
Компилятор PGI дает правильный результат и не приватизирует i
, С другой стороны, GCC правильно определяет, что p
должно быть firstprivate
но затем сталкивается с запретом в стандарте и выдает ошибку времени компиляции.
Если кто-то изменяет задачу следующим образом:
#pragma omp task shared(p)
{
...
}
он работает правильно с GCC, но задача выводит неверное начальное значение p
а затем вызывает ошибку сегментации как с компилятором Intel C ++, так и с компилятором PGI C ++.
Пойди разберись!
Других решений пока нет …