CUDA计划中的竞争条件

时间:2014-10-14 06:56:12

标签: gpu race-condition

我有两段代码。一个用C语言编写,用CUDA编写的相应操作。 请帮助我理解__syncthreads()如何在以下程序的上下文中工作。根据我的理解,__syncthreads()确保线程的同步仅限于一个块。

C程序:

{
    for(i=1;i<10000;i++)
    {
        t=a[i]+b[i];
        a[i-1]=t;
    }
}

`

等效的CUDA计划: `

__global__ void kernel0(int *b, int *a, int *t, int N)
{
    int b0=blockIdx.x;
    int t0=threadIdx.x;
    int tid=b0*blockDim.x+t0;
    int private_t;
    if(tid<10000)
    {
        private_t=a[tid]+b[tid];
        if(tid>1)
            a[tid-1]=private_t;
        __syncthreads();
        if(tid==9999)
        *t=private_t;
    }
}

内核维度:

dim3 k0_dimBlock(32);
dim3 k0_dimGrid(313);
kernel0 <<<k0_dimGrid, k0_dimBlock>>>

令人惊讶的事实是C和CUDA程序的输出是相同的。鉴于问题的性质,其具有[]对其自身的依赖性,a [i]由thrad-ID i加载并由同一线程写入[i-1]。现在,对于线程ID i-1也是如此。如果问题大小小于32,则输出很明显。但是对于大小为10000的块和块的问题,依赖如何得到尊重?

1 个答案:

答案 0 :(得分:0)

  

根据我的理解, __ syncthreads()可确保同步   线程限制在一个区块内。

你是对的。 __syncthreads()是块上下文中的同步障碍。因此,例如,在开始算法的下一阶段之前必须确保所有数据都已更新时,它非常有用。

  

鉴于问题的本质,它具有[]对自身的依赖性,   a [i]由线程ID i加载并由同一线程写入[i-1]。

想象一下线程2到达if语句,因为它匹配它输入语句的条件。现在线程执行以下操作:

private_t=a[2]+b[2];
a[1]=private_t;

女巫相当于:

a[1]=a[2]+b[2];

正如您所指出的,它是数组a的数据依赖。由于您无法在某些时候控制warp的执行顺序,因此您将使用a数组的更新版本。在我看来,您需要添加额外的__syncthreads()语句:

if( tid > 0 && tid<10000)
{
    private_t=a[tid]+b[tid];
    __syncthreads();
    a[tid-1]=private_t;
    __syncthreads();
    if(tid==9999)
    *t=private_t;
}

通过这种方式,每个线程使用原始数组private_t获得自己的a变量版本,然后并行更新数组。

关于* t值:

如果您只查看*t的值,则根据启动参数,您将不会注意到此随机调度的效果,因为带有tid==9999的线程可能位于最后一次扭曲以及线程tid==9998。由于创建private_t值所需的两个数组位置并且您已经具有该同步障碍,因此答案应该是正确的