我有两段代码。一个用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的块和块的问题,依赖如何得到尊重?
答案 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
值所需的两个数组位置并且您已经具有该同步障碍,因此答案应该是正确的