请在以下内核中解释内存访问的工作原理:
__global__ void kernel(float4 *a)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
float4 reg1, reg2;
reg1 = a[tid]; //each thread reads a unique memory location
for(int i = 0; i < totalThreadsNumber; i++)
{
reg2 = a[i]; //all running threads start reading
//the same global memory location
//some computations
}
for(int i = 0; i < totalThreadsNumber; i++)
{
a[i] = reg1; // all running threads start writing
//to the same global memory location
//race condition
}
}
它在第一个循环中如何工作?有序列化吗?我假设第二个循环导致线程序列化(仅在warp?中)并且结果是未定义的。
答案 0 :(得分:2)
保留我对Fermi(sm_2x)的解释,对于较旧的硬件内存访问,则为半经线。
在第一个循环(读取)中,整个warp从同一地址读取到局部变量。这导致“广播”。由于Fermi具有L1高速缓存,因此将加载一个高速缓存行,或者直接从高速缓存中获取数据(用于后续迭代)。换句话说,没有序列化。
在第二个循环(写入)中,哪个线程获胜是未定义的 - 就像任何多线程编程模型一样,如果多个线程写入同一位置,则程序员负责了解竞争条件。您无法控制块中的哪个warp将最后执行,也无法控制最后一个warp中的哪个线程将完成写入,因此您无法预测最终值将是什么。