DRD 的假阳性"Conflicting load"?

false positive "Conflicting load" with DRD?

本文关键字:Conflicting load DRD      更新时间:2023-10-16

用DRD(valgrind)分析我的C++代码发现了一个"冲突负载",但我不明白为什么。代码如下:

int* x;
int Nt = 2;
x = new int[Nt];
omp_set_num_threads(Nt);
#pragma omp parallel for
for (int i = 0; i < Nt; i++)
{
    x[i] = i;
}
for (int i = 0; i < Nt; i++)
{
    printf("%dn", x[i]);
}

该程序运行良好,但当主线程打印出x[1]的值时,DRD发现了一个问题。除了由于x数组的分配方式可能导致的错误共享外,我不明白为什么会有任何冲突,以及如何避免冲突……有什么见解吗?

EDIT这是上面代码的DRD输出(第47行对应于printf语句):

==2369== Conflicting load by thread 1 at 0x06031034 size 4
==2369==    at 0x4008AB: main (test.c:47)
==2369== Address 0x6031034 is at offset 4 from 0x6031030. Allocation context:
==2369==    at 0x4C2DCC7: operator new[](unsigned long) (vg_replace_malloc.c:363)
==2369==    by 0x400843: main (test.c:37)
==2369== Other segment start (thread 2)
==2369==    at 0x4C31EB8: pthread_mutex_unlock (drd_pthread_intercepts.c:703)
==2369==    by 0x4C2F00E: vgDrd_thread_wrapper (drd_pthread_intercepts.c:236)
==2369==    by 0x5868D95: start_thread (in /lib64/libpthread-2.15.so)
==2369==    by 0x5B6950C: clone (in /lib64/libc-2.15.so)
==2369== Other segment end (thread 2)
==2369==    at 0x5446846: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.7.3/libgomp.so.1.0.0)
==2369==    by 0x54450DD: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.7.3/libgomp.so.1.0.0)
==2369==    by 0x4C2F014: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==2369==    by 0x5868D95: start_thread (in /lib64/libpthread-2.15.so)
==2369==    by 0x5B6950C: clone (in /lib64/libc-2.15.so)

GNU OpenMP运行时(libgomp)使用线程池实现OpenMP线程团队。创建后,线程停靠在一个屏障上,等待唤醒以执行特定任务。在GCC中,这些任务以大纲(与内联相反)代码段的形式出现,即并行区域(或显式OpenMP任务)的代码被提取到一个单独的函数中,并作为执行任务提供给一些等待线程。然后,停靠屏障被提升,线程开始执行任务。一旦完成,线程将再次停靠——它们不是连接的,而是简单地挂起。因此,从DRD的角度来看,在并行区域之后执行代码的串行部分的主线程在没有保护的情况下访问其他线程可能写入的资源。当然,这是不可能发生的,因为其他线程已停靠并等待新任务。

这种误报在像DRD这样的通用工具中很常见,这些工具不理解OpenMP的特定语义。因此,这些工具不适合分析OpenMP程序。您应该使用专门的工具,例如Sun/Oracle Solaris Studio for Linux的免费"线程分析器"或商业版的"英特尔检查器"。后者可以在获得非商业开发许可的情况下免费使用。这两个工具都了解OpenMP的细节,不会出现可能的数据竞赛等情况。