我最近在编程中遇到了一个简单的概念,但是当我试图在cuda中实现它时我卡住了。
假设我有数千个元素,我想找到它们之间最接近的一对。我在全局内存中使用atomicMIN
(假设我们不想减少),因此如果每个线程计算的距离小于全局变量中存储的距离,则atomicCAS将用较小的值替换它。例如,我有全局变量float gbl_min_dist
为此,我使用以下代码:
__device__ inline float atomicMin(float *addr, float value){
float old = *addr, assumed;
if( old <= value ) return old;
do{
assumed = old;
old = atomicCAS((unsigned int*)addr, __float_as_int(assumed), __float_as_int(value));
}while( old!=assumed );
return old;
}
现在假设我们希望存储两个点的索引,它们更接近并且atomicMIN
已经成功地将旧的最小距离替换为由这两个点计算的最小距离点。我的意思是我只想存储当前距离较小的两个点的空位,当且仅当它的距离刚刚在全局变量中成功转换时
typedef struct {float gbl_min_dist,
unsigned int point1,
unsigned int point2;} global_closest_points;
所以在这里,当一个线程执行atomicMIN
时,如果要比较的那个脚步提出的值在gbl_min_dist
中交换,那么我还需要将p1,p2交换为来自线程的值。如果gbl_min_dist
未被交换,那么我不想存储点因为这会给出错误的点但是正确的最小距离。
是否有任何返回值来检查atomicCAS
是否已进行交换?
有关如何在atomicMIN
提前致谢
答案 0 :(得分:1)
您可以构建一个关键部分,以原子方式更新最小值和相应的点索引。以下链接提供了有关如何使用atomicCAS()
和atomicExch()
构建CS的示例。
https://github.com/ArchaeaSoftware/cudahandbook/blob/master/memory/spinlockReduction.cu
另一方面,我建议用并行缩减算法替换原子min操作。这可能会改善表现。
答案 1 :(得分:1)
gbl_min_dist
是32位值,如果您能找到将p1
和p2
同时压缩为单个32位值的方法,则可以使用像我给here。{/ li>那样的自定义原子学答案
醇>
如果您只是使用atomicCAS
是否进行了第一次交换来调整其他代码以更新p1
和p2
,我认为仍有可能存在允许竞争条件您的数据在线程更新之间不同步。
答案 2 :(得分:0)
我建议的方式是,不是依赖于存储的距离,而是在存储的点可能发生变化至关重要时重新计算它:
typedef struct {
unsigned int point1,
unsigned int point2;
}
global_closest_points, local_closest_points, temp_c_p;
local_dist = distance(local_closest_points.point1, local_closest_points.point2);
temp_c_p = global_closest_points;
while (local_dist < distance(temp_c_p.point1, temp_c_p.point2)
temp_c_p = atomicCAS(&global_closest_points, temp_c_p, local_closest_points);
旧的习惯是,而不是重新计算。但是对于现代处理器,这通常不是最佳的。在CUDA上,全局内存的原子更新比计算数百个双精度距离需要更多的时间。