到目前为止,我必须使用自制的gcc
在Mac上编译OMP增强的代码。
好消息是,Apple Clang现在可以找到OMP标头(至少在其Apple LLVM version 9.1.0 (clang-902.0.39.2)
版本中)。
坏消息是,过去用于工作的自定义归约子句不再有效。我已在下面附上了演示我的问题的代码段。进入带有段错误或以下错误的并行块时,它立即崩溃:
DebugOMP(46436,0x7fff8fc12380) malloc: *** error for object 0x7fff8fc02000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
有没有办法解决这个问题?像#pragma omp parallel for
这样的简单OMP子句可以正常工作。我正在使用Armadillo 9.100.5。本征也会发生同样的问题。
main.cpp:
#include <armadillo>
#pragma omp declare reduction( + : arma::vec : omp_out += omp_in ) \
initializer( omp_priv = omp_orig )
int main() {
int N = 10000;
int M = 100;
double a = 0;
// Built-in reduction, works
#pragma omp parallel for reduction(+:a)
for (int k = 0; k < M; ++k){
a += k;
}
std::cout << a << std::endl;
arma::vec v = arma::zeros<arma::vec>(M);
// Parallel access, works
#pragma omp parallel for
for (int k = 0; k < M; ++k){
v(k) = k;
}
std::cout << v << std::endl;
// Custom, reduction, segfaults
#pragma omp parallel for reduction(+:v)
for (int i = 0; i < N; ++i){
v += arma::ones<arma::vec>(v.n_rows);
}
std::cout << v << std::endl;
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.0.0)
# Building procedure
get_filename_component(dirName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
set(EXE_NAME ${dirName} CACHE STRING "Name of executable to be created.")
project(${EXE_NAME})
# Find Armadillo
find_package(Armadillo REQUIRED )
include_directories(${ARMADILLO_INCLUDE_DIRS})
# Find OpenMP
find_package(OpenMP)
if(OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
# Add source files in root directory
add_executable(${EXE_NAME}
main.cpp)
# Linking
set(library_dependencies ${ARMADILLO_LIBRARIES} )
target_link_libraries(${EXE_NAME} ${library_dependencies} OpenMP::OpenMP_CXX)
答案 0 :(得分:2)
您可以像这样手动进行缩小
#pragma omp parallel
{
arma::vec t = arma::zeros<arma::vec>(M);
#pragma omp for nowait
for (int i = 0; i < N; ++i) t += arma::ones<arma::vec>(v.n_rows);
#pragma omp critical
v += t;
}
适用于Clang。这可以帮助您弄清楚如何定义initializer-expr
例如,这适用于GCC 7
#pragma omp declare reduction( + : arma::vec : omp_out += omp_in ) \
initializer( omp_priv = arma::zeros<arma::vec>(omp_orig.n_rows))
但是对于Clang 5.0,代码会挂起,所以我不确定Clang的问题是什么。我尝试了其他initializer-expr变体,但没有一个能让Clang正常工作。
我安装了clang7,OP的代码运行正常。总的来说,我认为将向量明确设置为零是一个更好的主意
initializer( omp_priv = arma::zeros<arma::vec>(omp_orig.n_rows))
而不是像这样隐含
initializer(omp_priv = omp_orig)
因为隐式情况假定构造函数初始化为零。
答案 1 :(得分:1)
由于最初的问题也询问了Eigen,因此这是一个使用gcc 5、6、7、8和clang 6的独立示例。它使用clang 5进行段错误,可能是clang 5方面的错误。这与Z Boson提出的解决方案基本相同。
#include <Eigen/Core>
#include <iostream>
using namespace Eigen;
typedef VectorXd vec;
#pragma omp declare reduction( + : vec : omp_out += omp_in ) \
initializer( omp_priv = vec::Zero(omp_orig.size()) )
int main() {
int N = 10000;
int M = 100;
vec v = vec::LinSpaced(M,0,M-1);
#pragma omp parallel for reduction(+:v)
for (int i = 0; i < N; ++i){
v += vec::Ones(v.size());
}
std::cout << v.transpose() << std::endl;
return 0;
}