如何在C语言中使用OpenMP-MPI混合范式填充数组?运行异常求助
问题核心原因
- 最直接的错误是OpenMP并行区的变量属性设置错误:你把
test数组声明为了firstprivate变量。firstprivate的语义是每个OpenMP线程会独立复制一份原始test数组作为自己的私有变量,你在线程内修改的只是当前线程私有的副本,并行区执行结束后所有私有副本都会被销毁,主线程原始的test数组从头到尾都没有被修改过,最后打印的就是栈上未初始化的数组(栈内存默认值为0,所以输出全0)。你观察到的“每个线程能正确更新自己负责的元素、其余元素为0”也完全符合这个逻辑:每个线程的私有副本初始值都是全0,仅修改自己负责的位置,所以线程内打印会出现这个现象,但修改完全不会同步到主线程的公共数组。 - 如果是多MPI进程运行的场景,还有第二个问题:MPI是多进程编程模型,每个进程拥有独立的地址空间,哪怕你修正了OpenMP的问题,非0号进程的修改也只会存在于自身的
test数组中,不会自动同步到0号进程的数组里,你最后只打印0号进程的数组,自然拿不到其他进程的计算结果。 - 还有一个隐藏的越界风险:你定义的
test数组固定长度为6,但打印时循环上限是mpi_size*omp_size,如果启动的MPI进程数大于1,会发生数组越界访问,触发未定义行为。
修正方案
如果你是单MPI进程+多OpenMP线程的运行场景,只需要修改OpenMP编译制导语句的变量属性,把firstprivate(test)改成shared(test)即可,让所有OpenMP线程共享同一个test数组,修改直接作用于进程的公共数组:
// 修改后的并行区声明 #pragma omp parallel default(none) private(omp_rank) shared(mpi_size,mpi_rank,test)
修改后你就能得到预期的输出结果。
如果你是多MPI进程运行的场景,在修改上述OpenMP属性之外,还需要在并行区执行结束后调用MPI_Gather等集合通信接口,把所有进程的test分片汇总到0号进程的全局数组中,再统一打印。
内容的提问来源于stack exchange,提问作者Soham Mandal
相关产品推荐
相关产品推荐

