Cuda 原子乘法和除法?
有atomicAdd和atomicSub,但似乎atomicMul和atomicDiv不存在!可能吗?我需要实现以下代码:Cuda 原子乘法和除法?,cuda,Cuda,有atomicAdd和atomicSub,但似乎atomicMul和atomicDiv不存在!可能吗?我需要实现以下代码: atomicMul(&accumulation[index],value) 我该怎么办?好的,我解决了。但我无法理解atomicMul是如何工作的,我也不知道如何为float编写它 #include <stdio.h> #include <cuda_runtime.h> __device__ double atomicMul(doubl
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容易吗?怎么用?我必须用通配符*替换加号+吗?