为什么CUDA同步点不会阻止竞争条件?

时间:2016-04-25 06:07:06

标签: c++ cuda race-condition

我们在代码上运行cuda-memcheck --tool racecheck <executable>。我们得到以下内存危险错误。

========= Race reported between Read access at 0x00004098 CUDA.cu:123:KernelFunction()
=========     and Write access at 0x00005058 in CUDA.cu:146:KernelFunction() [529996 hazards]  

这是代码。它声称第123行value = sharedMemory0[sharedMemoryIndex];处于竞争状态,行146 sharedMemory0[sharedIndex0] = sharedMemory1[sharedIndex1];。我们有

// Synchronization Point 1 
__syncthreads(); 
__threadfence_block();

两条线之间。所有线程都不应该在该点同步,并且此时所有先前的内存读/写都完成了吗?在开始第二个j循环之前,所有线程和内存访问应在第一个j循环之后完成。因此,在我们看来,同步点1应该隔离两个j循环并防止竞争条件,但该工具说不是真的。

为什么该工具会报告竞争条件?关于我们可以做些什么来防止它的任何见解?

我们还看到了对可能能够报告执行痕迹的工具的引用,以便更容易地看到竞争条件。我们可以使用哪些工具和选项来更清楚地了解竞争条件存在的原因?

   for (i = 0; i < COUNT0; i++) {
       // Synchronization Point 0
       __syncthreads();
       __threadfence_block();
       for (j = 0; j < COUNT1; j++) {
          index = j*blockDim.x + threadIdx.x;
          if (index < THREAD_COUNT0) {
             for (k = 0; k < COUNT2; k++)
                sharedMemoryIndex = function0(index);
                value = sharedMemory0[sharedMemoryIndex];
             }
          }         
       }

       // Synchronization Point 1
       __syncthreads();
       __threadfence_block();
       for (j = 0; j < COUNT2; j++) {
          index = j*blockDim.x + threadIdx.x;
          if (index < THREAD_COUNT1) {
            sharedIndex0 = function1(index);
            sharedIndex1 = function2(index);
            sharedMemory0[sharedIndex0] = sharedMemory1[sharedIndex1];
          }
       }
    }

我们还运行了同步检查工具cuda-memcheck --tool synccheck <executable>,它在同步点1上报告了以下错误。这两个错误之间可能存在很强的相关性,但是并没有这样做。在cuda-memcheck指南中有很多关于不同代码的同步,它为什么不好以及如何修复它的文档。

有任何意见吗?

========= Barrier error detected. Encountered barrier with divergent threads in block
=========     at 0x00004ad8 in CUDA.cu:139:KernelFunction()
=========     by thread (0,0,0) in block (8,0,0)

2 个答案:

答案 0 :(得分:1)

没有足够的数据准确查明您的问题。但是,最后一条错误消息非常重要:

Barrier error detected. Encountered barrier with divergent threads in block

看起来一个块中的一个线程到达了一些障碍而另一个没有,因为它位于一个未被占用的分支中。注意,不同的分支不仅出现在if条件中,而且出现在循环中,如果它们的循环条件在块中的线程之间不同。

当某些线程错过__syncthreads()时,因为它可能会发生奇怪的事情。实际上,它通常意味着那些线程停在不同的 __syncthreads(),系统认为一切都是同步的。这可能会导致您描述的赛车情况。

所以 - 找到你的分歧__syncthreads() - 这很可能是你问题的原因。可能是问题是之前你所包含的片段。

此外:

  • i本地变量(不共享)?
  • 对于块中的所有线程,
  • COUNT0是否相同?

答案 1 :(得分:0)

此代码提供的结果与用于执行计算的线程数无关。我们只用一个线程运行代码,然后用多个线程运行代码。根据定义,单线程版本不可能遇到竞争条件。然而,单线程版本给出了与多线程版本相同的结果。 ResultSet在多线程版本上报告了许多违规行为。如果实际发生了种族违规,则多线程结果将与单线程结果完全不匹配。因此,cuda-memcheck --tool racecheck必定是错误的并且存在处理复杂循环结构的错误。 cuda-memcheck能够在简单的循环结构中找到竞争条件,而不是在这个复杂的循环结构中。