CUDA共享内存超过1个块停止工作

时间:2016-04-30 22:52:02

标签: cuda shared-memory

我正在使用共享内存为学校编写程序。我得到了正常工作的功能,但它只适用于每网格大小为1的块。如果每个网格有超过1个块,则该功能不再起作用。

例如,如果我发送一个大小为10的数组,包含1个块和10个线程,则此功能可正常工作。如果我发送相同的数组,每个块有2个块和5个线程,那么它就不再有效了。当我说不再有效时,我会收到我发送的相同阵列,退出,就像什么也没发生一样。

__global__ void rankSortShared(int* a, int n)
{
    int threadId = threadIdx.x + blockDim.x * blockIdx.x;
    int x = 0;

    // Make dynamic sized shared array
    // size will be determined from the 3rd parameter in the 
    // kernal call 'ranksortShared<<<blocksPerGrid, threadsPerBlock, *(size of shared mem)*>>>()'
    extern __shared__ int b[];

    // copy data from incomming array to shared array
    // then sync the threads so all threads have put their 
    // values into the shared array
    b[threadId] = a[threadId];
    __syncthreads();

    // now use shared array for faster lookups
    for (int j = 0; j < n; j++)
    {
        // handle duplicate values
        if (b[j] < b[threadId] || (b[threadId] == b[j] && j < threadId))
        {
            x++;
        }   
    }
    // put data back into array to be transferred back to CPU
    a[x] = b[threadId];
}

对于我的生活,我无法弄清楚为什么。是否有一种特殊的方法可以在多个块中使用共享内存?

为了尝试调试这个,我用a[threadId] = threadId替换了所有代码,并且数组看似正确(打印数字0到9)。所以,我不明白为什么如果threadId似乎是正确的,这不会起作用,并且它适用于1个块。

1 个答案:

答案 0 :(得分:2)

这里有一个问题:

int threadId = threadIdx.x + blockDim.x * blockIdx.x;
b[threadId] = ...;

您的threadId变量是全局唯一的线程索引。这意味着你在网格中包含的线程越多(例如通过更多的块),这个索引就越高。

但对于共享内存,每个块中的索引从零开始。因此,最终,当您添加更多块时,您的threadId变量将大于块中的共享内存量。

通常的解决方案是做这样的事情:

b[threadIdx.x] = ...;

因为threadIdx.x变量从每个块中的零开始。 (您可以使用此策略将{{>>每个出现的b[threadId]替换为b[threadIdx.x],而不仅仅是一次。)

您的代码中可能还有其他问题。由于您还没有显示完整的代码,因此无法诊断其他代码。

基于这样的陈述:

  

当我说不再有效时,我会收到我发送的相同阵列,退出,就像什么也没发生一样。

我的猜测是你没有做proper cuda error checking。在向别人寻求帮助之前,你应该真的这样做。即使你不理解错误输出,它也会帮助其他人试图帮助你。