如何在CUDA中使用atomicCAS用于带有条件的多个变量

时间:2013-10-14 14:52:21

标签: cuda atomic compare-and-swap

我最近在编程中遇到了一个简单的概念,但是当我试图在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

中实现此功能的任何想法

提前致谢

3 个答案:

答案 0 :(得分:1)

您可以构建一个关键部分,以原子方式更新最小值和相应的点索引。以下链接提供了有关如何使用atomicCAS()atomicExch()构建CS的示例。

https://github.com/ArchaeaSoftware/cudahandbook/blob/master/memory/spinlockReduction.cu

另一方面,我建议用并行缩减算法替换原子min操作。这可能会改善表现。

答案 1 :(得分:1)

  1. 您可以使用critical section让每个帖子在更新数据时拥有对数据的独占访问权。
  2. 由于您的gbl_min_dist是32位值,如果您能找到将p1p2同时压缩为单个32位值的方法,则可以使用像我给here。{/ li>那样的自定义原子学答案

    如果您只是使用atomicCAS是否进行了第一次交换来调整其他代码以更新p1p2,我认为仍有可能存在允许竞争条件您的数据在线程更新之间不同步。

答案 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上,全局内存的原子更新比计算数百个双精度距离需要更多的时间。