printf防止竞争条件

时间:2014-05-10 23:16:02

标签: c multithreading openmp race-condition

在此示例代码中,我执行从i=0i=n的求和,然后将结果添加到自身k次,其中k是线程数。我故意在没有critical(围绕printfans += ans)的情况下做到这一点,导致竞争条件。然而,令我惊讶的是,没有发生任何竞争条件:

int summation_with_operation_after_it_wrong1(int n, int k) {
        int ans = 0;
        #pragma omp parallel firstprivate(n) num_threads(k)
        {
                int i; /* Private */
                #pragma omp for schedule(dynamic) reduction(+:ans)
                for (i = 0; i < n; i++) {
                        ans += i;
                }
                printf("Thread %d ans=%d\n", omp_get_thread_num(), ans);
                ans += ans;    
        }
        return ans;
}

使用n=10k=4,输出(总是相同,除了线程顺序):

Thread 1 ans=45
Thread 3 ans=45
Thread 0 ans=45
Thread 2 ans=45
720

但是,我确实发现了一些奇怪的事情。 ans总是45,而不是

Thread 3 ans=45
Thread 0 ans=90
Thread 2 ans=180
Thread 1 ans=360
720

使用critical时。所以我将printf移到了ans += ans之后,看看它在做什么,而且,令我惊讶的是,预测的竞争条件一直开始发生!

Thread 3 ans=90
Thread 1 ans=135
Thread 2 ans=90
Thread 0 ans=135
135

那么...... printf如何阻止竞争条件?那个数额最终是如何达到720?我完全迷失在这里。

2 个答案:

答案 0 :(得分:2)

最新OpenMP standard的第1.4节规定了竞争条件的结果(强调我的):

  

如果多个线程在没有同步的情况下写入同一个内存   单位,包括由于所述的原子性考虑而引起的情况   在上面,然后发生数据竞争。同样,如果至少有一个线程   从内存单元读取,至少一个线程写入没有   同步到同一个内存单元,包括由于的情况   如上所述的原子性考虑,然后发生数据竞争。   如果发生数据争用,则无法指定程序的结果。

您注意到的内容与粗体语句完全一致。事实上,由于未指定包含数据争用的程序中的行为,因此争论为什么特定输出来自给定运行是没有意义的。特别是,只有在720命令之前插入printf时才获得ans+=ans,并且无法保证您始终会遇到相同的行为。

答案 1 :(得分:1)

printf()是一个非常昂贵的号召,使用它会改变你的竞争条件时机并不奇怪。查看发生了什么的更好选择是(预先)创建一个数组来存储结果,并让每个线程将其结果存入此阵列,您当前正在执行打印;在完成所有工作后,再做实际的printf()