CUDA环境下OpenMP无法多线程运行问题求助
问题:CUDA项目中OpenMP多线程无法正常启用
现象描述
编写CUDA版SGEMM程序时,其中基于OpenMP实现的CPU多线程SGEMM在CUDA项目中始终串行执行,omp_get_num_threads()返回1;但将该CPU代码单独提取到纯C项目编译运行时,多线程正常工作,omp_get_num_threads()返回8。CUDA项目与纯C项目的CPU代码完全一致,内存分配方式(new/cudaMallocHost)不影响该问题。
相关代码
CPU多线程SGEMM实现
void sgemm_cpu_multi_threading( float* A, float* B, float* C, float alpha, float beta, const int M, const int N, const int K ) { #pragma omp parallel for num_threads(8) for (int m = 0; m < M; m++) { printf("%d thread(s) can be used\n", omp_get_num_threads()); for (int n = 0; n < N; n++) { float psum = 0.0; for (int k = 0; k < K; k++) { psum += A[m * K + k] * B[k * N + n]; } C[m * N + n] = C[m * N + n] * beta + psum * alpha; } } } int main() { const int OMP_THREADS = 8; omp_set_num_threads(OMP_THREADS); // ... 内存分配、初始化等逻辑 sgemm_cpu_multi_threading(A, B, C, alpha, beta, M, N, K); // ... 后续处理 }
CUDA项目CMakeLists.txt
cmake_minimum_required(VERSION 3.10) project(SGEMM CUDA CXX) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -fopenmp") SET(COMPILE_CUDA True) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CUDA_ARCHITECTURES 75) find_package(OpenMP REQUIRED) if (OPENMP_FOUND) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() include_directories( ${CMAKE_SOURCE_DIR}/../ ) add_executable(matmul ./matmul.cu) target_link_libraries(matmul pthread OpenMP::OpenMP_CXX)
问题原因
- CUDA编译未传递OpenMP参数:nvcc编译
.cu文件时,会将CPU代码分离后调用宿主编译器(如gcc)处理,但当前CMake配置仅给CMAKE_CXX_FLAGS添加了OpenMP参数,未将这些参数传递给nvcc的编译流程。nvcc不会自动继承CMAKE_CXX_FLAGS的OpenMP选项,导致.cu文件中的CPU代码未启用OpenMP。 - 编译选项覆盖问题:手动设置
CMAKE_CXX_FLAGS_RELEASE时直接赋值,可能覆盖了后续find_package(OpenMP)添加的编译参数,导致OpenMP未被正确启用。
解决方案
修改CMakeLists.txt,为CUDA编译显式传递OpenMP参数,并调整编译选项的设置方式:
cmake_minimum_required(VERSION 3.10) project(SGEMM CUDA CXX) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CUDA_ARCHITECTURES 75) find_package(OpenMP REQUIRED) if (OPENMP_FOUND) # 为C/CXX添加OpenMP编译参数 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") # 将OpenMP参数传递给nvcc调用的宿主编译器 set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler ${OpenMP_CXX_FLAGS}") endif() # 用追加方式设置Release编译选项,避免覆盖已有参数 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} $ENV{CXXFLAGS} -O3 -Wall") set(CMAKE_CUDA_FLAGS_RELEASE "${CMAKE_CUDA_FLAGS_RELEASE} -O3") include_directories( ${CMAKE_SOURCE_DIR}/../ ) add_executable(matmul ./matmul.cu) target_link_libraries(matmul OpenMP::OpenMP_CXX)
关键改动说明
- 添加
CMAKE_CUDA_FLAGS设置,通过-Xcompiler将OpenMP参数传递给nvcc的宿主编译器,确保.cu文件中的CPU代码启用OpenMP。 - 调整
CMAKE_CXX_FLAGS_RELEASE的设置方式为追加,避免覆盖OpenMP相关参数。 - 移除不必要的
pthread链接(OpenMP::OpenMP_CXX已包含线程库依赖)。
内容的提问来源于stack exchange,提问作者Enigmatisms
相关产品推荐
相关产品推荐

