如何为结构体中的std::vector声明OpenMP归约?
问题:OpenMP归约结构体中的std::vector报错
尝试通过OpenMP自定义归约声明对结构体中的std::vector执行求和归约,代码如下:
// g++ -fopenmp MRE.cpp -o MRE #include <vector> #include <algorithm> #include <omp.h> struct Particles { std::vector<double> fx; }; #pragma omp declare reduction(vec_double_plus : std::vector<double> : \ std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>()) \ ) initializer(omp_priv = decltype(omp_orig)(omp_orig.size())) int main() { Particles particles; // Initialize fx vector with 100 elements for (int i = 0; i < 100; ++i){ particles.fx.push_back(0.0); } // Parallel region to set the values of fx #pragma omp parallel { // Thread-private local vector std::vector<double> thread_fx(particles.fx.size(), 0.0); #pragma omp for for (size_t i = 0; i < particles.fx.size(); ++i){ thread_fx[i] = 1.0; // Assign values to thread_fx } // Now we reduce thread_fx into particles.fx #pragma omp for reduction(vec_double_plus: particles.fx) for (size_t i = 0; i < particles.fx.size(); ++i) { particles.fx[i] += thread_fx[i]; } } return 0; }
但编译器报错,错误信息如下:
MRE.cpp: In function ‘int main()’: MRE.cpp:31:57: error: expected ‘)’ before ‘.’ token 31 | #pragma omp for reduction(vec_double_plus: particles.fx) | ^ | ) MRE.cpp:31:48: error: user defined reduction not found for ‘particles’ 31 | #pragma omp for reduction(vec_double_plus: particles.fx)
请问如何专门为结构体中的std::vector声明归约子句?
解决方法
错误根源
OpenMP的reduction子句不支持直接使用成员访问表达式(如particles.fx)作为归约变量,它要求变量是一个独立的标识符。另外你代码中第二个omp for属于逻辑冗余——归约操作不需要手动循环累加,OpenMP会自动处理合并逻辑。
方法一:用临时变量作为桥梁
先将结构体中的vector赋值给临时变量,对临时变量执行归约,完成后再将结果写回结构体成员:
// g++ -fopenmp MRE.cpp -o MRE #include <vector> #include <algorithm> #include <omp.h> struct Particles { std::vector<double> fx; }; #pragma omp declare reduction(vec_double_plus : std::vector<double> : \ std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>()) \ ) initializer(omp_priv = decltype(omp_orig)(omp_orig.size())) int main() { Particles particles; // Initialize fx vector with 100 elements for (int i = 0; i < 100; ++i){ particles.fx.push_back(0.0); } // 用临时变量承接结构体的vector std::vector<double>& temp_fx = particles.fx; #pragma omp parallel reduction(vec_double_plus: temp_fx) { // Thread-private local vector std::vector<double> thread_fx(temp_fx.size(), 0.0); #pragma omp for for (size_t i = 0; i < temp_fx.size(); ++i){ thread_fx[i] = 1.0; } // 直接将线程私有vector合并到临时变量(归约操作) std::transform(temp_fx.begin(), temp_fx.end(), thread_fx.begin(), temp_fx.begin(), std::plus<double>()); } return 0; }
方法二:为结构体类型声明自定义归约
如果需要频繁对Particles结构体的fx成员做归约,可以直接为结构体类型声明归约规则:
// g++ -fopenmp MRE.cpp -o MRE #include <vector> #include <algorithm> #include <omp.h> struct Particles { std::vector<double> fx; }; // 直接为Particles结构体声明归约,指定对fx成员执行vector求和 #pragma omp declare reduction(particles_fx_plus : Particles : \ std::transform(omp_out.fx.begin(), omp_out.fx.end(), omp_in.fx.begin(), omp_out.fx.begin(), std::plus<double>()) \ ) initializer(omp_priv.fx = decltype(omp_orig.fx)(omp_orig.fx.size())) int main() { Particles particles; // Initialize fx vector with 100 elements for (int i = 0; i < 100; ++i){ particles.fx.push_back(0.0); } #pragma omp parallel reduction(particles_fx_plus: particles) { // Thread-private local vector std::vector<double> thread_fx(particles.fx.size(), 0.0); #pragma omp for for (size_t i = 0; i < particles.fx.size(); ++i){ thread_fx[i] = 1.0; } // 构造临时Particles对象,将线程私有vector赋值给它的fx成员 Particles temp_part; temp_part.fx = std::move(thread_fx); // 合并到全局particles(归约操作) std::transform(particles.fx.begin(), particles.fx.end(), temp_part.fx.begin(), particles.fx.begin(), std::plus<double>()); } return 0; }
内容的提问来源于stack exchange,提问作者Stefan de Souza
相关产品推荐
相关产品推荐

