【问题标题】:C++ OpenMP computation errors with private and shared clause私有和共享子句的 C++ OpenMP 计算错误
【发布时间】:2018-01-30 15:27:34
【问题描述】:

我有一个for 循环要与 OpenMP 并行化,但有多个计算错误,可能是由于我对 OpenMP 的多线程概念缺乏了解:

for ( int i = -X/2; i < X/2; ++i )
{
    base.y = anchor + i*rho_step;
    temp = some_function( base );
    if( temp > response )
    {
        buffer.y = base.y;
        response = temp;
    }
}

这很好,然后我做了以下更改:

#pragma omp parallel for shared (buffer, response) private(base, temp)
for ( int i = -X/2; i < X/2; ++i )
{
    base.y = anchor + i*rho_step;
    temp = some_function( base );
    if( temp > response )
    {
        buffer.y = base.y;
        response = temp;
    }
}

在这段代码中,buffer.yresponse 都没有正确的值。据我了解,每个线程都应该有自己的base.ytemp 副本,它们只是计算的临时变量,bufferresponse 必须共享(它们将存储计算数据),但这并不像我预期的那样工作。

唯一完美的版本是以下,但显然没有性能提升:

omp_lock_t writelock;
omp_init_lock(&writelock);
omp_set_num_threads (4);

#pragma omp parallel for
for ( int i = -X/2; i < X/2; ++i )
{
    omp_set_lock(&writelock);
    base.y = anchor + i*rho_step;
    temp = some_function( base );
    if( temp > response )
    {
        buffer.y = base.y;
        response = temp;
    }
    omp_unset_lock(&writelock);
}
omp_destroy_lock(&writelock);

可能是什么问题? (anchorrho_step 是这个循环中的常量)

【问题讨论】:

  • 对我来说,似乎存在数据依赖关系:response 可能会改变并直接影响以后的循环传递。如果是这样,您将无法使用任何多线程工具轻松加速循环。只有some_function需要很多时间的时候,加多线程才是有用的。
  • response 仅在 if 条件为真的情况下发生变化。 some_function 做了很多事情,这就是我试图节省运行时间的原因。感谢您的评论!

标签: c++ multithreading openmp


【解决方案1】:

为了让您的代码处理bufferresponse 变量的跨线程,您需要为它们使用一些每个线程的局部变量,并对它们执行最终归约以更新他们的共享副本。

这是它的样子(未经测试):

#pragma omp parallel firstprivate( base )
{
    auto localResponse = response;
    auto localBuffer = buffer;
    #pragma omp for
    for ( int i = -X/2; i < X/2; ++i )
    {
        base.y = anchor + i * rho_step;
        auto temp = some_function( base );
        if ( temp > localResponse )
        {
            localBuffer.y = base.y;
            localResponse = temp;
        }
    }
    #pragma omp critical
    {
        if ( localResponse > response )
        {
            buffer.y = localBuffer.y;
            response = localResponse;
        }
    }
}

【讨论】:

  • 不幸的是,这产生了相同的结果。如果bufferresponse 是共享的并且处于临界区,我不明白为什么我们需要每个线程的局部变量。对于每个不同的i,我们有不同的base.ytemp,我们只需要管理每个线程都有自己的base.y-s和temp-s,并检查它们是否需要修改bufferresponse 一个接一个。 (对不起,我的知识不完善。)
  • 我只是做了一个更改,添加了base firstprivate,因为不清楚其他字段在上下文中是否重要。无论如何,我的方法的重点是最终的归约(critical 部分)在并行循环之外,但在并行部分内。它在最后只发生一次,而不是像在您的代码中那样在每次迭代中发生......
  • firstprivate 解决了这个问题,现在你和我的版本都可以了,谢谢!
  • 请注意,尽管您的版本会遇到变量bufferresponse 的竞争条件(这是制作本地版本并在critical 部分进行最终缩减的重点) .因此,尽管您的版本似乎适用于 firstprivate,但它本质上是错误的。
猜你喜欢
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 2019-04-16
  • 1970-01-01
相关资源
最近更新 更多