2013-04-18 36 views
8

私はGPUでプロジェクトをやっていますが、cudaはdoubleをサポートしていないため、atomicAdd()をdoubleに使う必要があります。 。atomicAdd()for double for GPU

__device__ double atomicAdd(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); 
} 

は今、私は実装がアトミックに実行することができない負荷を、必要とするので、基本的に

答えて

9

(!=古いと仮定)しながら、実装は、ループを必要とする理由を知りたいです。比較交換操作は

(*address == assumed) ? (assumed + val) : *address 

の原子版ですaddressの値は値がaddressからロードされるサイクルとatomicCAS呼び出しがあるサイクルの間で変更されないという保証はありません更新された値を格納するために使用されます。その場合、addressの値は更新されません。したがって、ループは、読み取りと比較およびスワップ操作の間の値の変更がなくなるまで(つまり、更新が行われたことを意味する)、2つの操作が繰り返されることを保証します。

+0

ありがとうございました!あなたはロード操作が仮定されている=古い、原子的でないことを意味するので、アトミック関数old = atomicCAS(address_as_ull、仮定、__ double_as_long(val + __ longlong_as_double(仮定)))変更する必要があります。また、add()は再度行う必要があります。 – taoyuanjl

+3

いいえ、 'old'はスレッドローカル変数です。ローカルスレッドがそれを変更しない限り、その値は変更されません。変更できる唯一の値は、スレッド制御の外側では '* address'です。操作中に別のスレッドによって変更された場合、 'atomicCAS'呼び出しを繰り返す必要があります。そうでない場合、更新は行われません。 – talonmies

+0

私はそれを持って、ループの機能は、* address_as_ullの変更の現在の値が現在のスレッドによって行われることを保証します。 – taoyuanjl