c++ - Clang、OpenMP 和自定义向量/矩阵缩减
问题描述
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
有没有办法解决这种减少?更简单的 OMP 子句可以#pragma omp parallel for
正常工作。我正在使用犰狳 9.100.5。Eigen 也会出现同样的问题。
主.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)
解决方案
您可以像这样手动进行减少
#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)
因为隐式情况假定构造函数初始化为零。
推荐阅读
- c# - .NET DataContractJsonSerializer 日期时间格式
- python - pickle.load 错误:UnicodeDecodeError:“utf8”编解码器无法解码字节...无效的起始字节
- python - 如何从 df1 中删除 df2 中标识的行?
- asp.net - 未找到 HTTP 错误 404.17 - Windows Svr 2016 上的 IIS 10
- java - 在 Eclipse RCP 中向 CompletionProposal 添加样式(内容辅助)
- makefile - 如何使用多个可执行文件为 fortran 编写 makefile
- salesforce - 无法让基本 HTTP 发布在 Salesforce Apex 标注中工作
- java - 为什么二次时间算法比线性时间算法执行得更快
- r - 具有分类数据的泊松 GLM
- swift - 我可以将字符串转换为 SINCall 吗?