OpenMP计算前缀和时出现重复线程、结果错误问题排查
问题根因
核心原因是变量共享/私有属性未正确配置引发的数据竞争:
- OpenMP中在并行区域外声明的变量默认属于所有线程共享,你的代码中
i、j、t、somme四个变量都是共享变量 - 多个线程同时读写共享变量时会互相覆盖取值,比如线程A刚给
t赋值为自己的线程号,还没执行打印,线程B就把t改成了自己的线程号,最终就会出现线程号重复的现象;同理j、somme被多个线程同时修改时,内层循环的计数、求和结果都会出现不可预期的错误,和你贴出的异常表现完全吻合。
修复方案
有两种常用的修复方式,都是让每个线程持有自己私有版本的循环变量、临时求和变量、线程号变量即可:
方案1:显式指定私有变量
在OpenMP并行指令后加private子句,声明对应变量为线程私有:
#include <stdio.h> #include <omp.h> #define n 16 int main(void) { int a[n] = {2,3,6,9,4,7,0,2,2,6,8,9,11,0,2,4}; int i, j, t, somme; #pragma omp parallel num_threads(16) private(i,j,t,somme) #pragma omp for for (i=0; i<n; i++){ t = omp_get_thread_num(); somme = a[0]; for (j=1; j<i+1; j++) somme += a[j]; printf("<%d>: S(%d) = %d\n", t, i, somme); } return 0; }
方案2:把变量声明放到并行区域内部
C99及以上标准支持在for循环头、并行块内部声明变量,这类变量天然就是线程私有,不需要额外加private子句:
#include <stdio.h> #include <omp.h> #define n 16 int main(void) { int a[n] = {2,3,6,9,4,7,0,2,2,6,8,9,11,0,2,4}; #pragma omp parallel num_threads(16) #pragma omp for for (int i=0; i<n; i++){ int t = omp_get_thread_num(); int somme = a[0]; for (int j=1; j<i+1; j++) somme += a[j]; printf("<%d>: S(%d) = %d\n", t, i, somme); } return 0; }
补充说明
当前你实现的前缀和是O(n²)时间复杂度,仅适合小数据量验证使用;如果需要处理大规模数据,可以改用并行前缀和的标准实现,时间复杂度可降到O(log n),性能会高很多。
内容的提问来源于stack exchange,提问作者aryaz
相关产品推荐
相关产品推荐

