有atomicAdd和atomicSub,但似乎atomicMul和atomicDiv不存在!可能吗?我需要实现以下代码:
atomicMul(&accumulation[index],value)
我该怎么办?
答案 0 :(得分:0)
好的,我解决了。但是我无法理解atomicMul是如何工作的,我不知道如何为浮点数写它。
#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;
}
答案 1 :(得分:0)
根据我对atomicCAS
的理解,我会补充horus的答案。我的回答可能是错误的,因为我没有查看atomicCAS
函数,只是阅读了有关它的文档(atomicCAS,Atomic Functions)。随意解决我的问题。
atomicMul如何运作
根据我的理解,atomicCAS(int* address, int compare, int val)
的行为如下。
*address
复制到old
(即old = *address
)(old == compare ? val : old)
存储到*address
。 (此时,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
读取值(其值为eqaul到address_as_ull
),然后将一些值乘以它然后再写回来。问题是其他线程可以在读取,修改和写入之间访问和修改*address
的值。
为了确保没有其他线程的拦截,我们检查*address
的值是否等于我们assumed
的值。假设*address
和assumed=oldValue
之后其他线程修改了oldValue = atomicCAS(...)
的值。修改后的*address
值将被复制到old
内的atomicCAS
变量(请参阅上面atomicCAS
的行为1.)。
由于atomicCAS
根据*address
更新*address = (old == compare ? val : old)
,*address
将不会更改(old==*address
)。
然后atomicCAS
返回old
并进入oldValue
,以便循环可以继续,我们可以在下一次迭代尝试另一次拍摄。如果在读取和写入之间未修改*address
,则会将val
写入*address
,并且循环将结束。
如何为浮动写
简短回答:
__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 long
到int
,因为float
的大小与int
匹配。