OpenMP omp parallel if子句传参0/1时输出不符合预期问题
OpenMP parallel if子句结果不符合预期的原因分析
核心规则说明
你遇到的结果和预期相反,不是if子句的语义和文档不符,是代码嵌套了两层parallel指令,触发了OpenMP默认配置的两个规则:
#pragma omp parallel if(expr)的语义本身没有反转:- 表达式
expr求值为非0(逻辑真):当前parallel区域正常创建多线程组,并行执行区域代码 - 表达式
expr求值为0(逻辑假):当前parallel区域不创建新线程,由当前线程串行执行区域代码
- 表达式
- OpenMP默认关闭嵌套并行(对应
OMP_NESTED环境变量默认值为false):如果代码已经运行在一个活跃的并行区域内部,再遇到#pragma omp parallel指令,内层parallel不会创建新线程,只会由进入该指令的当前线程串行跑完内层全部代码,此时在内层调用omp_get_thread_num()会固定返回0。
对应测试代码的场景拆解
输入i=0时的执行逻辑
外层#pragma omp parallel if(i)判断条件为0,外层parallel不创建新线程,由初始主线程串行执行外层大括号内的代码。
此时主线程不在任何活跃并行区域中,遇到内层#pragma omp parallel num_threads(5)时会正常创建5个线程并行执行,每个线程拿到0~4的线程号,分别给对应下标的c数组赋值打印,所以输出是c[0]=7到c[4]=15的5条结果。
输入i=1时的执行逻辑
外层#pragma omp parallel if(i)判断条件为非0,外层parallel正常创建线程组,你当前运行环境默认的并行线程数正好是5,5个外层线程并行执行外层大括号内的代码。
每个外层线程执行到内层#pragma omp parallel num_threads(5)时,因为嵌套并行默认关闭,内层不会创建新线程,每个外层线程都会串行执行一遍内层代码:在内层串行上下文里omp_get_thread_num()固定返回0,因此每个外层线程都会给c[0]赋值7并打印,最终输出5行一模一样的c[0] = 7。
修正方案
不需要嵌套两层parallel,直接把if判断加到实际要执行计算的parallel层即可,同时建议把线程号变量声明为线程私有,避免多线程数据竞争:
#include<omp.h> #include<stdio.h> int main(){ int a[5] = {1, 2, 3, 4, 5} ; int b[5] = {6, 7, 8, 9, 10} ; int c[5]; int i; scanf("%d", &i); #pragma omp parallel num_threads(5) if(i) { int tid = omp_get_thread_num(); // 声明在并行区域内,每个线程私有 c[tid] = a[tid] + b[tid]; printf("c[%d] = %d\n", tid, c[tid]); } return 0; }
修正后执行效果符合预期:
- 输入i=1:if条件成立,5个线程并行执行,输出0~4下标对应的c数组值
- 输入i=0:if条件不成立,主线程串行执行,仅输出1行
c[0] = 7
内容的提问来源于stack exchange,提问作者k201083 Muhammad Rayan Ali
相关产品推荐
相关产品推荐

