并行化 for 循环执行数组赋值时的问题

问题描述 投票:0回答:2

我正在学习omp并遇到这个问题...... 考虑以下代码:

  1. 数组
    a
    b
    c
    已初始化
#pragma omp parallel num_threads(4)
{
    #pragma omp for schedule(static, 64)
    for(int i = 0; i < 256; i++)
    {
        d[i] = a[i];
        if( i + 1 < 256 )
            d[i+1] = b[i];
        if( i + 2 < 256 )
            d[i+2] = c[i];
    }
}

多次运行此代码时,注意到以下观察结果:

  1. 看到随机结果(正确/不正确)
  2. 不正确的值被分配给索引
    d
    =64 或
    i
    =128
     处的 
    i

考虑到分配的线程数量 (4) 和迭代次数 (256),我应用了块大小为 64 的

schedule(static, 64)
。我假设使用
static
进行调度将使线程按顺序运行。我什至在作业上应用了
#pragma omp critical
,但这不起作用,随机行为仍然存在。

c++ visual-studio-2015 openmp variable-assignment schedule
2个回答
3
投票

您的

schedule(static, 64)
仅表明 256 次迭代应以 64 次为一组进行分发,但它无法确定哪个线程将负责团队中线程之间的哪个迭代 以循环方式进行(OpenMP-API 11.5) .3
schedule
子句),并且它不保证线程将以任何固定顺序执行。我发现这两篇文章很好地解释了这一点:

所以,你有一个竞争条件+数据竞争(谢谢Joachim)。即使你添加了,你仍然会遇到这些问题

        #pragma omp critical
        d[i] = a[i];
        if( i + 1 < 256 )
            #pragma omp critical
            d[i+1] = b[i];
        if( i + 2 < 256 )
            #pragma omp critical
            d[i+2] = c[i];

这意味着一次只允许 1 个线程执行这 3 条指令之一。但考虑到执行迭代 69 的线程 1 在线上

d[i+1] = b[i];
上,执行迭代 68 的线程 2 在线上
d[i+2] = c[i];
上。仍然是比赛状态。


0
投票

通过添加 OpenMP 指令,您可以断言代码在并行执行时不会出现数据争用。 该代码具有循环携带依赖性,这将导致并行执行期间的数据竞争。您可以轻松地将循环转换为无依赖性(因此无数据竞争)循环:

#pragma omp parallel num_threads(4)
{
    #pragma omp for schedule(static, 64)
    for(int i = 0; i < 256; i++)
    {
        d[i] = a[i];
        /* apply i:=i-1 to move the access to d into the same iteration */
        if( i < 256 && i - 1 >= 0 )
            d[i] = b[i - 1];
        /* apply i:=i-2 to move the access to d into the same iteration */
        if( i < 256 && i - 2 >= 0 )
            d[i] = c[i - 2];
    }
}

此转换解决了代码中的数据争用,而无需添加进一步的同步。编译器应该能够自动应用此类转换,并且实际上执行此类转换以向量化代码。由于您断言使用 OpenMP 不需要进行此类转换,因此编译器将不会应用该转换。

© www.soinside.com 2019 - 2024. All rights reserved.