【问题标题】:OpenMP about for loopOpenMP 关于 for 循环
【发布时间】:2019-08-01 14:36:57
【问题描述】:

我有一个 OpenMP 代码 sn-p 如下:

#ifdef _OPENMP
  #pragma omp parallel for default(none) \
  private(i, a_output) \
  shared(n, t_input, t0, trace_amp)
#endif
    for (i = 0; i < n; i++){
        if( t_input >= t0[i] )
        {

                a_output = trace_amp[i];

                return a_output;
        }
    }

这段代码正确吗?为什么a_output 必须是私有的?可以分享吗?

【问题讨论】:

  • 在问这里之前你问过编译器吗?
  • 在循环中包含 return 语句会使您的程序不符合(OpenMP)要求,因为您正在从并行区域分支出来。
  • 你必须更具体的问题标题:)

标签: c for-loop openmp


【解决方案1】:

正如@1201ProgramAlarm 所说,您不能在并行区域内有return 语句。编译器甚至不编译代码

$ gcc Untitled-1.c -fopenmp
Untitled-1.c: In function ‘main’:
Untitled-1.c:7:20: error: invalid branch to/from OpenMP structured block
             return a_output;

$ clang Untitled-1.c -fopenmp=libomp
Untitled-1.c:7:13: error: cannot return from OpenMP region
            return a_output;
            ^
1 error generated.

但是,OpenMP 规范 4.0 版带来了一个新指令:cancel。使用它,您可以中断并行区域的执行。它给总执行时间增加了一点开销,因为在每次迭代中,线程都会测试它们是否必须停止。

你可以尝试用这种方式重写原来的for循环:

  a_output = 0;
#ifdef _OPENMP
  #pragma omp parallel default(none) \
  private(i) \
  shared(n, t_input, t0, trace_amp, a_output)
  #pragma omp for
#endif
  for (i = 0; i < n; i++){
      if( t_input >= t0[i] ){
              a_output = trace_amp[i];
              #pragma omp cancel for
      }
      #pragma omp cancellation point for

  }
  return a_output;

您必须将forparallel 分开以避免在for 上使用隐式nowait 子句

编辑:如@Zulan所述

1) 如果发生取消,必须至少有一个所有线程可以自然到达的取消点。尽管cancel 指令本身根据定义有一个取消点,但它位于一个可能不会被所有线程访问的 if 语句中。解决方案是在 if 语句之外添加 cancellation point。我更改了代码以匹配此。

2) 在大多数运行时默认情况下禁用取消。要启用,应将OMP_CANCELLATION 环境变量设置为true。

3) a_output 中仍有竞争条件。除非您确定在t0 内只有一个值小于t_input,否则在取消发生之前有两个或更多线程将写入a_output。您应该查看代码背后的逻辑,以确认这是否存在问题。

【讨论】:

  • 感谢您的解决方案。
  • 1) 取消仅在取消点有效(您的示例中没有)2) 默认禁用取消,3) 代码在a_output 上仍然存在竞争条件。
猜你喜欢
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
  • 2012-07-31
  • 2022-01-19
相关资源
最近更新 更多