atomicAddとatomicSubがありますが、atomicMulとatomicDivは存在しないようです!出来ますか?次のコードを実装する必要があります。原子の乗算と除算?
atomicMul(&accumulation[index],value)
どうすればいいですか?
atomicAddとatomicSubがありますが、atomicMulとatomicDivは存在しないようです!出来ますか?次のコードを実装する必要があります。原子の乗算と除算?
atomicMul(&accumulation[index],value)
どうすればいいですか?
[OK]を解決しました。しかし、私は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;
}
私がatomicCAS
について理解したことに基づいてhorusの回答を補足します。 atomicCAS
の機能を調べていないのに、それに関する文書(atomicCAS、Atomic Functions)を読んだだけで、私の答えは間違っている可能性があります。私の答えには自由に対処してください。
atomicMulが私の理解によると
の仕組み、atomicCAS(int* address, int compare, int val)
の動作は以下の通りです。 *address
からold
に
*address
(すなわちold = *address
)(old == compare ? val : old)
。 (この時点では、old
と*address
の値は、条件が一致したか否かによって異なる場合があります。)atomicMul
関数の定義を見たときにその行動についての理解old
が良くなります。私たちが何をしたいのか
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
から値を読み込む(その値はaddress_as_ull
にeqaulである)、およびそれにいくつかの値を乗算してから戻ってそれを書きます。問題は、他のスレッドがread、modify、writeの間で値*address
にアクセスして変更できることです。
*address
の値がassumed
と等しいかどうかを確認するために、他のスレッドの切片がないことを確認します。 assumed=oldValue
とoldValue = atomicCAS(...)
の後に他のスレッドが*address
の値を変更したとします。 *address
の変更された値は、内の変数old
にコピーされます(上記の動作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
型に整数型にフロート/ double型の変数を変換する必要があります。私は上記変更したことint
へfloat
マッチのサイズのでint
にfloat
とunsigned long long
からdouble
です。
プログラミングガイド 'の点で任意のアトミック操作を表現する方法[実施例](http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#atomic-functions)を有していますatomicCAS() 'あなたはアンの答えを書きたい場合は – tera
@tera私は例を見 –
をupvoteだろう。これは、atomicAddをdoubleに実装しますが、新しいアトミック算術演算子を実装しません。 atomicMulを作成するためにこの例を変更するのは簡単ですか?どうやって?プラス記号+をワイルドカード*に置き換える必要がありますか? – horus