我有一个初始化的共享内存数组如下
#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
或已经具有唯一值,则它必须只读出唯一值。棘手的部分是array
和count
必须都只能由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];
这里有一些棘手的并发性。我不确定这适用于所有情况。有更好的建议或意见吗?
答案 0 :(得分:2)
根据您的描述,array
元素将被写入的唯一时间是它是否包含值UNDEFINED
。我们可以利用这个。
线程首先会在所需的atomicCAS
元素上执行array
operation。 atomicCAS
将配置为检查UNDEFINED
值。如果它存在,它将用DEFINED
替换它。如果不存在,则不会替换它。
根据atomicCAS
的返回结果,线程将知道数组元素是否包含UNDEFINED
。如果确实如此,那么atomicCAS
的返回结果将为UNDEFINED
,然后线程将从count
开始并从中检索所需的唯一值,并使用它来修改DEFINED
1}}值到所需的唯一值。
我们可以在一行代码中执行此操作:
// 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中检索为函数,因此您根本不需要扫描