Cuda 原子乘法和除法?

Cuda 原子乘法和除法?,cuda,Cuda,有atomicAdd和atomicSub,但似乎atomicMul和atomicDiv不存在!可能吗?我需要实现以下代码: atomicMul(&accumulation[index],value) 我该怎么办?好的,我解决了。但我无法理解atomicMul是如何工作的,我也不知道如何为float编写它 #include <stdio.h> #include <cuda_runtime.h> __device__ double atomicMul(doubl

有atomicAdd和atomicSub,但似乎atomicMul和atomicDiv不存在!可能吗?我需要实现以下代码:

 atomicMul(&accumulation[index],value)

我该怎么办?好的,我解决了。但我无法理解atomicMul是如何工作的,我也不知道如何为float编写它

#include <stdio.h>
#include <cuda_runtime.h>

__device__ double atomicMul(double* address, double val) 
{ 
  unsigned long long int* address_as_ull = (unsigned long long int*)address; 
  unsigned long long int old = *address_as_ull, assumed; 
  do { 
 assumed = old; 
 old = atomicCAS(address_as_ull, assumed, __double_as_longlong(val * __longlong_as_double(assumed))); 
 } while (assumed != old); return __longlong_as_double(old);
}      
__global__ void try_atomicMul(double* d_a, double* d_out)
{
     atomicMul(d_out,d_a[threadIdx.x]);
} 
int main()
{
  double h_a[]={5,6,7,8}, h_out=1;
  double *d_a, *d_out;

 cudaMalloc((void **)&d_a, 4 * sizeof(double));
 cudaMalloc((void **)&d_out,sizeof(double));

 cudaMemcpy(d_a, h_a, 4 * sizeof(double),cudaMemcpyHostToDevice);
 cudaMemcpy(d_out, &h_out, sizeof(double),cudaMemcpyHostToDevice);

 dim3 blockDim(4);
 dim3 gridDim(1);

  try_atomicMul<<<gridDim, blockDim>>>(d_a,d_out);
 cudaMemcpy(&h_out, d_out, sizeof(double), cudaMemcpyDeviceToHost);

 printf("%f \n",h_out);
 cudaFree(d_a);
 return 0;
}
#包括
#包括
__设备双原子(双*地址,双val)
{ 
无符号长整型*地址作为(无符号长整型*)地址;
无符号long long int old=*假定地址为ull;
做{
假定=旧;
old=原子(地址为ull,假设为,地址为double,地址为longlong(val*,地址为double,假设为));
}while(假定为!=old);将u longlong_返回为_double(old);
}      
__全局\uuuuuvoid try\u atomicMul(双*d\u a,双*d\u out)
{
atomicMul(d_out,d_a[threadIdx.x]);
} 
int main()
{
双h_a[]={5,6,7,8},h_out=1;
双倍*d_a,*d_out;
Cudamaloc((无效**)和d_a,4*sizeof(双倍));
Cudamaloc((无效**)和d_out,sizeof(双重));
cudaMemcpy(d_a,h_a,4*sizeof(双精度),cudamemcpyhostodevice);
cudaMemcpy(d_out和h_out,sizeof(double),cudamemcpyhostodevice);
dim3区块DIM(4);
dim3网格DIM(1);
试试原子弹(d_a,d_out);
cudaMemcpy(&h_out,d_out,sizeof(double),cudamemcpydevicetoost);
printf(“%f\n”,h\u out);
库达弗里(杜阿);
返回0;
}

我将根据我对
atomicCAS
的理解补充荷鲁斯的答案。我的答案在细节上可能是错误的,因为我没有查看
atomicCAS
函数,只是阅读了有关它的文档(,)。请随意回答我的问题

atomicMul如何工作

根据我的理解,
atomicCAS(int*address,int compare,int val)
的行为如下

  • *地址
    复制到
    旧地址
    (即
    old=*地址
  • (old==比较?val:old)
    存储到
    *地址
    。(此时,
    old
    *address
    的值可能会有所不同,具体取决于条件是否匹配。)
  • 返回
    old
  • 当我们一起查看
    atomicMul
    函数的定义时,对其行为的理解会更好

    unsigned long long int* address_as_ull = (unsigned long long int*)address; 
    unsigned long long int oldValue = *address_as_ull, assumed; // Modified the name 'old' to 'oldValue' because it can be confused with 'old' inside the atomicCAS. 
    do { 
      assumed = oldValue; 
      // other threads can access and modify value of *address_as_ull between upper and lower line. 
      oldValue = atomicCAS(address_as_ull, assumed, __double_as_longlong(val * 
                           __longlong_as_double(assumed))); 
    } while (assumed != oldValue); return __longlong_as_double(oldValue);
    
    我们要做的是从
    地址
    读取值(其值等于
    地址
    ),然后将一些值乘以它,然后将其写回。问题是其他线程可以在读取、修改和写入之间访问和修改
    *地址
    的值

    为了确保没有截获其他线程,我们检查
    *address
    的值是否等于我们假设的值。假设另一个线程在
    假定=oldValue
    oldValue=atomicCAS(…)
    之后修改了
    *地址的值。
    *地址
    的修改值将被复制到
    atomicCAS
    中的
    old
    变量中(请参见上文
    atomicCAS
    的行为1)。 由于
    atomicCAS
    根据
    *地址=(旧==比较?val:old)
    更新
    *地址
    *地址
    将不会更改(
    旧==地址

    然后
    atomicCAS
    返回
    old
    并进入
    oldValue
    ,这样循环可以继续,我们可以在下一次迭代中尝试另一个镜头。当在读和写之间未修改
    *地址
    时,将
    val
    写入
    *地址
    ,循环将结束

    如何为float编写它

    简短答复:

    __device__ float atomicMul(float* address, float val) 
    { 
      int* address_as_int = (int*)address; 
      int old = *address_as_int, assumed; 
      do { 
        assumed = old; 
        old = atomicCAS(address_as_int, assumed, __float_as_int(val * 
    __float_as_int(assumed))); 
     } while (assumed != old); return __int_as_float(old);
    }
    
    我没有测试它,所以可能有一些错误。如果我错了,请纠正我

    它是如何工作的:
    由于某些原因,
    atomicCAS
    仅支持整数类型。因此,我们应该手动将float/double类型变量转换为整数类型以输入函数,然后将整数结果重新转换为
    float
    /
    double
    类型。我在上面修改的是
    double
    float
    unsigned long
    int
    ,因为
    float
    的大小与
    int
    匹配

    编程指南中有一个如何用
    atomicCAS()
    @tera来表达任意原子操作的方法如果你想写ann的答案,我想upvoteI看到了这个例子。它为double实现了atomicAdd,但没有实现新的原子算术运算符。修改这个示例以创建atomicMul容易吗?怎么用?我必须用通配符*替换加号+吗?