CUDA程序的控制流程

CUDA程序的控制流程,cuda,parallel-processing,nvidia,Cuda,Parallel Processing,Nvidia,下面是我编写的一个小程序,旨在了解CUDA比赛条件是如何发生的,但我对输出结果感到惊讶 #include<cutil.h> #include<iostream> __global__ void testLocal(int *something, int val[]){ *something = *something/2; val[threadIdx.x] = *something; } void main(){ int *a, *c; int

下面是我编写的一个小程序,旨在了解CUDA比赛条件是如何发生的,但我对输出结果感到惊讶

#include<cutil.h>
#include<iostream>
__global__ void testLocal(int *something, int val[]){

 *something = *something/2;


 val[threadIdx.x] = *something;
}

void main(){

    int *a, *c;
    int r =16;

    cudaMalloc((void**)&a, 4*sizeof(int));
    cudaMalloc((void**)&c, sizeof(int));
    cudaMemcpy(c, &r, sizeof(int) , cudaMemcpyHostToDevice);
    testLocal<<<1,4>>>(c,a);
    int *b = (int *)malloc(4 * sizeof(int));
    cudaMemcpy(b,a, 4 * sizeof(int), cudaMemcpyDeviceToHost);

    for( int  j =0 ; j< 4; j++){
        printf("%d\n",b[j]);

    }
    getchar();


}
#包括
#包括
__全局\uuuvoid testLocal(int*something,int val[]){
*something=*something/2;
val[threadIdx.x]=*某物;
}
void main(){
int*a,*c;
int r=16;
Cudamaloc((void**)和a,4*sizeof(int));
Cudamaloc((void**)和c,sizeof(int));
cudaMemcpy(c,&r,sizeof(int),cudamemcpyhostodevice);
testLocal(c,a);
int*b=(int*)malloc(4*sizeof(int));
cudaMemcpy(b,a,4*sizeof(int),cudaMemcpyDeviceToHost);
对于(int j=0;j<4;j++){
printf(“%d\n”,b[j]);
}
getchar();
}

当我启动4个线程时,我希望每个线程将*除以2一次。我知道他们划分的顺序不是固定的。因此,当我试图打印这些值时,我希望其中一个打印的值是8,一个是4,一个是2,一个是1。然而,所有打印值均为8。为什么会这样?不是所有线程都应该一次分割某个对象。

您看到的是未定义的行为。因为要启动一个包含4个线程的块,所以所有线程都在同一个扭曲中执行。这意味着

 *something = *something/2;
正在由已启动的所有线程同时执行。CUDA编程模型仅保证当来自同一个扭曲的多个线程尝试写入同一个内存位置时,其中一个写入操作将成功。它没有说明哪个线程会成功,以及扭曲中其他未“赢”的线程会发生什么情况。要获得您期望的行为,需要串行内存访问——这只有通过在支持原子内存访问原语的体系结构上使用原子内存访问原语才能实现。

应该是一个强有力的词。您正在做的是未指定的,所以它不应该做任何特定的事情

现在,它可能会在同一个计算单元上,在同一个扭曲内运行4个线程。(SIMT模型使每条线作为扭曲的一部分运行)。由于对
某物的操作不是原子操作,因此扭曲中的所有线程都会在锁定步骤中读取和写入内存。因此,这4个线程一起读取
*某物
,然后将结果除以2,并尝试将8写入内存


您所期望的是,可以通过原子操作来读写一些东西,尽管CUDA中没有可用的原子除法或乘法。因此,如果您真的想要这个,您需要编写自己的(在atomicCAS的帮助下)。您将开始看到您的性能急剧下降,因为您现在正在强制尝试并行运行的线程串行运行。

锁定步骤意味着什么?如果它们遵循锁机制,那么执行是原子锁步骤意味着所有线程同时执行同一条指令。事实上,如果使用CPU命名法,就相当于只有一个线程作为4宽SIMD执行。一条指令从内存中读取4个“线程”,一条指令进行除法,一条指令写入4个值(到同一内存位置)。