Openmp 程序在没有临界区的情况下工作

Posted

技术标签:

【中文标题】Openmp 程序在没有临界区的情况下工作【英文标题】:Openmp program works without critical section 【发布时间】:2019-02-24 13:02:43 【问题描述】:

在 Openmp 讲座中,类似的代码显示为 Openmp 中的竞争条件。在 for 循环中 sum+= 不在临界区,因此线程执行的顺序会改变结果。

但在我的程序中并非如此。无论我多久运行一次这个程序,总和总是打印为 285 (1²+2²+3²+4²+5²+6²+7²+8²+9²)。我的程序中似乎根本没有任何竞态条件。

 int main()
    
        int sum = 0;
        int a[10];
        int b[10];
        for (int counter = 0; counter < 10; counter++) 
            a[counter] = counter;
            b[counter] = counter;
        


#pragma omp parallel for shared(sum)
    for (int i = 0; i < 10; i++) 
        sum += a[i] * b[i];  
    
    cout << "sum is " << sum; // always prints 285
    std::cin.get();
    return 0;

讲座特别告诉我,这个程序不应该打印正确的总和。为了解决这个问题,他们告诉我们使用#pragma omp criticalreduction(+:sum)

【问题讨论】:

仅仅因为它在带有 your 编译器和 your 编译器选项的 your 机器上没有表现出错误行为 not 表示没有错误。不同的编译器、不同的优化选项或不同的硬件很可能会暴露该错误。 Jesper 的评论是正确答案。如果您想知道竞态条件不会影响系统结果的具体原因。您必须在问题中包含您的编译器版本、编译标志和特定系统配置。 您的编译器可能会查看循环计数并发现并行化是无效的。 @ForceBru 竞争条件也与这样一个事实有关,即如果不使用同步,变量的读者可能会看到该变量处于部分更改的状态。 @ForceBru sum 可能会在一个线程中特别更新,然后另一个线程写入它,然后第一个线程完成写入,导致最终不正确的值 sum 【参考方案1】:

仅仅因为它没有在 your 机器上使用 your 编译器和 your 编译器选项表现出错误行为not 表示没有错误。

不同的编译器、不同的优化选项或不同的硬件很可能会暴露该错误。

竞争条件很棘手,因为在许多情况或许多配置中,它们通常不会真正表现为问题(除非在您最大的客户深夜生产数月后)。 竞争条件仍然是错误和未定义的行为(这意味着您的编译器可以假设它们不存在,并且可能实际上使用该假设并因此巧妙地错误编译程序的其他部分)。

事实是,当多个线程正在修改同一个变量时(或者一些正在修改而一些正在读取),您需要同步访问共享变量 - 总是 - 不参加比赛。

【讨论】:

以上是关于Openmp 程序在没有临界区的情况下工作的主要内容,如果未能解决你的问题,请参考以下文章

读者写者问题(读者优先 写者优先 读写公平)

读者写者问题(读者优先 写者优先 读写公平)

多线程程序的临界区

互斥锁- pthread_mutex

线程中的临界区的应用

线程同步(windows平台):临界区