OpenMP中使用SIMD线性和并行线性指令时出现异常行为

4

我正在学习如何使用GNU C编译器6.2.1和C++来使用OpenMP,并测试了以下代码:

#include <stdio.h>
#include <omp.h>
#include <iostream>

int b=10;

int main()
{
    int array[8];
    std::cout << "Test with #pragma omp simd linear:\n";
    #pragma omp simd linear(b)
    for (int n=0;n<8;++n) array[n]=b;

    for (int n=0;n<8;++n) printf("Iteration %d: %d\n", n, array[n]);

    std::cout << "Test with #pragma omp parallel for linear:\n";
    #pragma omp parallel for linear(b)
    for (int n=0;n<8;++n) array[n]=b;

    for (int n=0;n<8;++n) printf("Iteration %d: %d\n", n, array[n]);
}

在这两种情况下,我都期望得到一个从10到17的数字列表,但事实并非如此。对于#pragma omp simd linear(b),它被直接忽略,只为array中的每个值打印10。对于#pragma omp parallel for linear(b),程序输出10,10,12,12,14,14,16,16
我使用g++ -fopenmp -Wall main.cpp -o main.o编译文件。我该如何解决这个问题?
编辑:仔细阅读规范后,我发现linear条款将初始值覆盖为最后一个获得的值(即如果我们从b=10开始,在第一次循环后,我们有b=17)。然而,如果我在并行循环中添加schedule(dynamic),程序就可以正确运行。为什么我必须指定该参数才能正确执行?

这非常有趣。在GCC5.4.0上可以重现此问题,除了GCC的openmp不接受没有simd从句的linear从句(测试代码的后一半无法在GCC上编译)。为了让b在GCC上发生变化,我使用了#pragma omp parallel for simd linear(b),但是每个线程内部,b的值仍然是固定的。您可以提交错误报告并向GCC团队或其他编译器开发人员组提问。 - user3528438
1个回答

3

OpenMP规范中说:

linear子句声明一个或多个列表项为私有,并且与出现在该子句上的结构体的迭代空间具有线性关系。

这只是向编译器提供了一个变量在循环中的线性行为的信息,但在你的代码中,b根本没有增加。这就是你在第一个循环中始终得到 10 的原因。因此,奇怪的结果并不是编译器的错。要更正它,你必须使用 array[n]=b++;

另一方面,对于 #pragma omp parallel for linear(b) 循环,OpenMP会为每个线程计算起始的 b 值(基于线性关系),但该值在给定线程中仍然没有增加。因此,根据使用的线程数,你将看到不同数量的“步骤”。

schedule(dynamic)子句的情况下,chunk_size1,因此每个循环周期在不同的线程中运行。在这种情况下,初始的b值总是由OpenMP计算得出,因此你只会得到正确的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接