【问题标题】:"invalid controlling predicate" compiler error using OpenMP使用 OpenMP 的“无效控制谓词”编译器错误
【发布时间】:2026-01-01 09:50:01
【问题描述】:

我正在创建一个基于 C - determine if a number is prime 的基本素数检查器,但使用的是 OpenMP。

int isPrime(int value)
{
    omp_set_num_threads(4);

    #pragma omp parallel for 
    for( int j = 2;  j * j <= value; j++)
    {
    if ( value % j == 0) return 0;
    }
    return value;
}

使用 -fopenmp 编译时,GCC 版本 4.7.2 出错,针对 for 循环声明 invalid controlling predicate

看起来这个错误是由 for 循环中的 j 平方引起的。有没有办法可以解决这个问题,并且仍然可以从算法中获得所需的输出?

【问题讨论】:

  • 您确定在开放式 mp 循环结构中允许使用 return 语句吗?
  • 不幸的是,使用 OpenMP 将循环并行化并不能帮助使用试除法测试单个素数。但是,您可以使用试除法有效地使用它来测试多个素数。但是,为了查找素数列表,我推荐使用埃拉托色尼筛法。这是使用 OpenMP 的版本create.stephan-brumme.com/eratosthenes
  • 另外,在您的isPrime 函数中,我建议使用j &lt;= j/value 而不是j*j &lt;= value,这可能会溢出rosettacode.org/wiki/Primality_by_trial_division#C

标签: c openmp


【解决方案1】:

return 不允许在循环内,因为它会导致在花括号之前退出。

注意下面给出的定义:

来自 OpenMP V2.5 规范,1.2.2 OpenMP 语言术语,p2:17-

结构化块 - 对于 C/C++,可执行语句,可能 复合式,顶部有一个入口,底部有一个出口 底部。

结构化块以打开的{ 开始,以结束的} 结束。 return 包含在这些大括号中,因此该程序也违反了结构化块的 OpenMP 定义,因为它有两个出口(一个在 return 处,一个在通过大括号的出口处)

OpenMP 对可以线程化的循环设置了以下五个限制:

  • 循环变量必须是有符号整数类型。无符号整数, 例如 DWORD 的,将不起作用。
  • 比较操作的形式必须是loop_variable &lt;, &lt;=, &gt;, 或&gt;=loop_invariant_integer
  • for 循环的第三个表达式或增量部分必须是 整数加法或整数减法并通过循环 不变的值。
  • 如果比较操作是&lt;&lt;=,循环变量必须 每次迭代递增,反之,如果比较 操作是&gt;&gt;=,循环变量必须递减 迭代。
  • 循环必须是基本块,这意味着没有从内部跳转 除了出口外,允许到外部的循环 语句,终止整个应用程序。如果语句 使用 goto 或 break,它们必须在循环内跳转,而不是在循环外 它。异常处理也是如此;必须捕获异常 在循环内。

【讨论】:

  • 我不明白为什么必须对循环变量进行签名。如果您需要一个大于有符号 8 字节数的整数怎么办?
【解决方案2】:

根据 OpenMP 标准(第 2.5.1 节,第 40 页),for 循环的控制谓词的可接受形式是:

  • var 关系运算 b
  • b 关系运算变量

您对j * j &lt;= value 的使用明显违反了此要求。基本原理是它要求编译器在运行时发出计算 value 的整数平方根的代码,而后者对于 value 的某些值是未定义的,特别是对于负数。

您可以将j * j &lt;= value 替换为j &lt;= sqrt_value,其中sqrt_valuevalue 的整数平方根,但是在循环内的结构化块中存在替代退出路径会出现问题。不幸的是,在这种情况下没有简单的解决方案,因为 OpenMP 不支持提前终止并行循环。

【讨论】: