【问题标题】:openmp: race condition in for loop and critical sectionopenmp:for循环和临界区中的竞争条件
【发布时间】:2021-12-09 11:13:11
【问题描述】:

在运行大量线程时,我的程序出现了不可预知的错误,我试图通过插入关键部分来找出问题所在。现在我要进行以下操作

void A::func()
{
 #pragma omp parallel for
 for (int i=0; i<100; ++i)
  {
    #pragma omp critical
    results[i] = compute(i);
  }
}

这仍然给我带来了我正在努力寻找的问题。我可以让它消失的唯一方法是删除 for 循环的并行化(不是很理想!)。

注意compute 函数很复杂,实际上使用了一些缓存。如果该代码中存在问题,我不会感到惊讶,但由于整个事情现在处于关键部分,我无法理解发生了什么。

我正在尝试调试的实际 for 循环位于 https://github.com/UCL/STIR/blob/49c65340a2116834fea6a9a5cb17f73eb4a6f259/src/scatter_buildblock/ScatterSimulation.cxx#L179-L198。仍然有问题的测试版本(接近上例)是here

注意:我首先在一个更复杂的场景中发布了这个,但我删除了that post,因为 1)我的简单示例没有显示问题,2)这个场景更加令人费解。

添加了更多信息。我正在使用 Ryzen 9 5900 在 Windows 10 上尝试此操作。我的测试代码显示 WSL2/Ubuntu 20.04 上的 gcc-8 和 gcc-9 偶尔出现问题。 (我观察到 Windows 上的 VS 2019 和 WSL2/Ubuntu 20.04 上的 clang-13 都没有问题,但我猜这并不意味着太多)。

【问题讨论】:

    标签: openmp race-condition


    【解决方案1】:

    这是来自 github 的有问题的代码 sn-p。

    #ifdef STIR_OPENMP
    #pragma omp parallel for reduction(+:total_scatter) schedule(dynamic)
    #endif
    
        for (int i = 0; i < static_cast<int>(all_bins.size()); ++i)
        {
            const Bin bin = all_bins[i];
            const double scatter_ratio = scatter_estimate(bin);
    
    #if defined STIR_OPENMP 
    #  if _OPENMP >= 201107
    #    pragma omp atomic write
    #  else
    #    pragma omp critical(ScatterSimulationByBin_process_data_for_view_segment_num)
    #  endif
    #endif
            viewgram[bin.axial_pos_num()][bin.tangential_pos_num()] =
                    static_cast<float>(scatter_ratio);
            total_scatter += static_cast<double>(scatter_ratio);
        } // end loop over bins
    

    这些是您的问题的可能原因:

    1. scatter_estimate 不是线程安全的。如果是这种情况,在函数之前使用#pragma omp critical 会解决它。
    2. bin.axial_pos_num()bin.tangential_pos_num() 不是线程安全的。请同时检查这些内容。
    3. 结果取决于循环的执行顺序。如果不同的i 给出相同的索引(即bin.axial_pos_num()bin.tangential_pos_num()),那么不同的执行顺序可能会产生不同的结果,因为您以不同的顺序覆盖viewgram 数组的相同元素。 请注意,如果是这种情况,则可能是您的算法存在缺陷。

    【讨论】:

    • 感谢@laci。 1.确实,scatter_estimate 可能不是线程安全的,这正是我想要找出的。把它放在#pragma omp critical 没有帮助。 2. bin.* 只是读取访问权限,所以应该没问题,但是使用 critical 部分而不是 atomic write 并没有帮助。所以我更进一步,把整个事情放在一个关键部分,但这也无济于事。我将编辑帖子以使其更清楚。仍然是 3。就我而言,ibins 之间的关系是独一无二的,但我想我的缓存中可能有一些取决于顺序的东西(这将是一个错误......)。
    • 以相反的顺序尝试你的循环(不使用 OpenMP),如果你得到不同的结果,你就发现了你的问题。
    • 谢谢@Laci。订购它!仔细查看我的代码,我对float 精度不足的常见问题很敏感。我没有看到,对于我测试的大多数数字,对顺序的依赖真的很小,但显然对某些人来说并非如此!转到double 似乎已经解决了这个问题。
    猜你喜欢
    • 2019-08-15
    • 2018-07-24
    • 1970-01-01
    • 2017-03-24
    • 2012-01-01
    • 2020-04-16
    • 2020-07-12
    • 2017-01-23
    • 1970-01-01
    相关资源
    最近更新 更多