如何同时写入和读取具有唯一递增值的CUDA数组?

时间:2016-01-15 19:04:56

标签: cuda

我有一个初始化的共享内存数组如下

#define UNDEFINED 0xffffffff
#define DEFINED   0xfffffffe

__shared__ unsigned int array[100];
__shared__ count;

// We have enough threads: blockDim.x > 100
array[threadIdx.x] = UNDEFINED;


// Initialize count
if (threadIdx.x == 0)
  count = 0;

线程可以随机访问array。当线程访问array时,如果它是UNDEFINED,则它必须向该元素写入唯一值count,然后读取该值。如果数组元素是DEFINED或已经具有唯一值,则它必须只读出唯一值。棘手的部分是arraycount必须都只能由1个线程更新。原子函数只更新1变量而不是2.这是我最终想出的方法,一个线程更新两个变量,同时阻止其他线程,直到完成。

value = atomicCAS(&array[randomIndex], UNDEFINED, DEFINED);
if (value == UNDEFINED) {
    value = atomicAdd(&count, 1);
    array[randomIndex] = value;
} 

// For case that value == DEFINED_SOURCe, wait for memory
// writes, then store value
__threadfence_block();
value = array[randomSource];

这里有一些棘手的并发性。我不确定这适用于所有情况。有更好的建议或意见吗?

2 个答案:

答案 0 :(得分:2)

根据您的描述,array元素将被写入的唯一时间是它是否包含值UNDEFINED。我们可以利用这个。

  1. 线程首先会在所需的atomicCAS元素上执行array operationatomicCAS将配置为检查UNDEFINED值。如果它存在,它将用DEFINED替换它。如果不存在,则不会替换它。

  2. 根据atomicCAS的返回结果,线程将知道数组元素是否包含UNDEFINED。如果确实如此,那么atomicCAS的返回结果将为UNDEFINED,然后线程将从count开始并从中检索所需的唯一值,并使用它来修改DEFINED 1}}值到所需的唯一值。

  3. 我们可以在一行代码中执行此操作:

    // assume idx contains the desired offset into array
    if (atomicCAS(array+idx, UNDEFINED, DEFINED) == UNDEFINED) array[idx]=atomicAdd(&count, 1);
    

    更完整的代码可能是这样的:

    value = DEFINED;
    while (value == DEFINED){
      value = atomicCAS(&array[randomIndex], UNDEFINED, DEFINED);
      if (value == UNDEFINED) {
        value = atomicAdd(&count, 1);
        array[randomIndex] = value;}
      }
    
     // value now contains the unique value, 
     // either that was already present in array[randomIndex] 
     // or the value that was just written there
    

答案 1 :(得分:0)

要获得递增值数组,请使用 prefx-sum ,也称为扫描算法,基于二叉树功率线程。首先是本地块(名称中的共享内存)?然后全局超过块,然后将每个汇总添加回每个块。 此外,对于每个来说,读取不是一个而是一些值可能是有效的,例如,物理上的“warp size”等于16 int值(我道歉,因为我已经做了很长时间了以前并且不知道CUDA中这个东西的正确尺寸和专有名称。 啊,顺便说一句,在相同增量的情况下,最终值可以从本地或全局thread.id中检索为函数,因此您根本不需要扫描