为什么OpenMP不允许使用!=运算符?

我试图编译下面的代码:

#pragma omp parallel shared (j) { #pragma omp for schedule(dynamic) for(i = 0; i != j; i++) { // do something } } 

我得到这个错误: 错误:无效的控制谓词

我检查了openMP 参考指南 ,它说并行为“only”允许以下操作符之一:<=>> =。

我不明白为什么不让i != j 。 我可以理解,如果这是静态的时间表,因为openMP需要预先计算分配给每个线程的迭代次数。 但我不明白为什么这种限制在这种情况下,例如。 任何线索?


编辑:即使我作出for(i = 0; i != 100; i++) ,虽然我可以把“<”或“<=”。

我给OpenMP开发者发送了关于这个主题的电子邮件,我得到的答案是:

对于signed int,绕回行为是未定义的。 如果我们允许!= ,程序员可能会得到意想不到的tripcount。 问题是编译器是否可以生成代码来计算循环的跳闸计数。

对于一个简单的循环,如:

 for( i = 0; i < n; ++i ) 

如果n> = 0 ,编译器可以确定有'n'次迭代, 如果n <0 ,编译器可以确定有0次迭代。

对于如下循环:

 for( i = 0; i != n; ++i ) 

再次, 如果n> = 0 ,编译器应该能够确定有“n”次迭代; 如果n <0 ,我们不知道它有多less次迭代。

对于如下循环:

 for( i = 0; i < n; i += 2 ) 

如果n> = 0 ,则编译器可以生成代码来计算跳闸计数(循环迭代计数)作为floor((n + 1)/ 2)如果n <0 ,则编译器计算0

对于如下循环:

 for( i = 0; i != n; i += 2 ) 

编译器无法确定'i'是否会打'n'。 如果“n”是一个奇数呢?

对于如下循环:

 for( i = 0; i < n; i += k ) 

如果n> = 0 ,编译器可以生成代码来计算跳闸计数为floor((n + k-1)/ k)如果n <0 ,则编译器知道该循环必须计数; 在这种情况下,如果k <0 ,这不是合法的OpenMP程序。

对于如下循环:

 for( i = 0; i != n; i += k ) 

编译器甚至不知道我是否正在计数。 它不知道'我'是否会打'N'。 这可能是一个无限循环。

积分 :OpenMP ARB

相反,它可能看起来像schedule(dynamic)不适用于dynamic数量的元素。 迭代块分配给线程是dynamic的。 在静态调度中,这个赋值是在工作共享结构开始时预先计算的。 通过dynamic调度,迭代块以先到先得的方式发送给线程。

OpenMP标准很清楚,一旦碰到工作共享结构,迭代的数量就会被预先计算,因此循环计数器可能不会在循环体内被修改(OpenMP 3.1规范,§2.5.1 – 循环构造):

在进入最外层循环之前计算每个相关循环的迭代次数。 如果执行任何关联的循环更改用于计算任何迭代计数的任何值,则行为是未指定的。

用于计算折叠循环的迭代计数的整数types(或种类,用于Fortran)是实现定义的。

工作共享循环具有编号为0,1,…,N-1的逻辑迭代,其中N是循环迭代的次数,并且逻辑编号表示如果执行相关联的循环,则迭代将被执行的序列由一个单一的线程。 schedule子句指定相关循环的迭代如何被划分为连续的非空子集,称为块,以及这些块如何分布在团队的线程之间。 每个线程在其隐式任务的上下文中执行其分配的块。 chunk_sizeexpression式是使用循环结构中私有的任何variables的原始列表项来计算的。 这个expression的评估的副作用是以什么次序或多less次来确定的,这是不明确的。 在循环结构的schedule子句expression式中使用variables会导致对所有封闭结构中的variables进行隐式引用。

这些关系运算符限制背后的基本原理非常简单 – 它提供了循环方向的明确指示,它允许轻松计算迭代次数,并且在C / C ++和Fortran中提供了OpenMP工作共享指令的类似语义。 另外其他的关系操作也需要仔细检查循环体,以便了解循环是如何进行的,在许多情况下这将是不可能的,并且会使执行变得麻烦。

OpenMP 3.0引入了显式task构造,允许并行迭代次数未知的循环。 但有一个问题:任务引入了一些严重的开销,每循环迭代一个任务只有在这些迭代需要执行很长时间时才有意义。 否则,开销将主宰执行时间。

答案很简单。 OpenMP不允许提前终止一组线程。 使用==或!=时,OpenMP无法确定循环何时停止。 1.一个或多个线程可能会遇到终止条件,这可能不是唯一的。 2. OpenMP无法closures可能永远不会检测到条件的其他线程。

如果我看到这个说法

 for(i = 0; i != j; i++) 

用来代替陈述

 for(i = 0; i < j; i++) 

我想知道为什么程序员做出了这个select,不要介意它可能意味着同样的事情。 OpenMP可能会做出一个严格的句法select,以强制代码的某种清晰度。

这是代码,它提出了使用!=挑战,并可能有助于解释为什么它不被允许。

 #include <cstdio> int main(){ int j=10; #pragma omp parallel for for(int i = 0; i < j; i++){ printf("%d\n",i++); } } 

注意ifor语句和循环内部都增加了,这导致了无限循环的可能性(但不是保证)。

如果谓词<那么循环的行为仍然可以在并行上下文中定义良好,编译器不必在循环中检查对i更改,并确定这些更改将如何影响循环的界限。

如果谓词是!=那么循环的行为就不再被很好地定义,并且可能在无限的范围内,从而阻止了简单的并行细分。

我认为除了扩展已有的function以达到这个目的外,可能没有什么好的理由。

IIRC原来这些必须是静态的,以便它可以在编译时确定如何生成循环代码…它可能只是一个宿醉。