如何同时写入和读取具有唯一递增值的CUDA数组?
我有一个共享内存数组,初始化如下如何同时写入和读取具有唯一递增值的CUDA数组?,cuda,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 ==
#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;
线程可以随机访问数组
。当线程访问数组
时,如果它是未定义的
,它必须向该元素写入一个唯一的值count
,然后读取该值。如果数组元素已定义或已具有唯一值,则必须仅读取唯一值。棘手的部分是array
和count
都必须只更新一个线程。原子函数只更新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];
这里有一些棘手的并发问题。我不确定这是否适用于所有情况。有更好的建议或意见吗?要获得递增值数组,请使用基于二叉树线程的prefx sum(也称为扫描算法)。优先于本地块(名称中的共享内存)?然后全局覆盖块,然后将每个总和添加回每个块。 此外,每个块读取的不是一个而是一些值可能是有效的,这些值等于物理上的“扭曲大小”,例如16个int值(我很抱歉,因为我很久以前就做过这件事,不知道CUDA中这件事的正确大小和正确名称)。
啊,顺便说一句,如果增量相等,最终值可以作为函数从local或global thread.id中检索,因此您根本不需要扫描。对于增量值数组,请使用prefx sum,也称为扫描算法,基于二叉树线程。优先于本地块(名称中的共享内存)?然后全局覆盖块,然后将每个总和添加回每个块。 此外,每个块读取的不是一个而是一些值可能是有效的,这些值等于物理上的“扭曲大小”,例如16个int值(我很抱歉,因为我很久以前就做过这件事,不知道CUDA中这件事的正确大小和正确名称)。
啊,顺便说一句,如果是等额递增,最终值可以作为函数从local或global thread.id中检索,因此您根本不需要扫描。根据您的描述,写入
数组
元素的唯一时间是如果它包含值未定义
。我们可以利用这一点
数组元素执行atomicCAS
。atomicCAS
将配置为检查未定义的值。如果存在,它将替换为定义的
。如果它不存在,它将不会替换它
atomicCAS
的返回结果,线程将知道数组元素是否包含UNDEFINED
。如果执行了,则来自atomicCAS
的返回结果将是未定义的
,然后线程将从计数
中检索所需的唯一值,并使用该值将已定义的
值修改为所需的唯一值// 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
根据您的描述,写入
数组
元素的唯一时间是它包含值未定义
。我们可以利用这一点
数组元素执行atomicCAS
。atomicCAS
将配置为检查未定义的值。如果存在,它将替换为定义的
。如果它不存在,它将不会替换它
atomicCAS
的返回结果,线程将知道数组元素是否包含UNDEFINED
。如果执行了,则来自atomicCAS
的返回结果将是未定义的
,然后线程将从计数
中检索所需的唯一值,并使用该值将已定义的
值修改为所需的唯一值// 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
我不想保持一个连续的总数。我只是尝试将唯一的递增值写入随机和并发访问的数组。若那个唯一的值已经写入到那个元素中,那个么就直接读出它。若块中的所有线程都会做不同的事情,那个么这将比普通处理器慢得多,尤其是现代的4核处理器,不管怎样。不过,如果你愿意的话,看看CUDA原子操作的完整列表,我会看看关于XOR的东西,随便什么。我记得CUDA中有一种阻止线程的semafores。我不想保持一个运行的总和。我只是尝试将唯一的递增值写入随机和并发访问的数组。若那个唯一的值已经写入到那个元素中,那个么就直接读出它。若块中的所有线程都会做不同的事情,那个么这将比普通处理器慢得多,尤其是现代的4核处理器,不管怎样。但是如果你愿意的话,看看CUDA原子操作的完整列表,我会看看关于XOR的东西,不管什么。我记得CUDA中有一种阻止线程的semafores。正在接近解决方案。但可能仍然存在一个问题。如果两个线程同时使用相同的idx值访问该语句,那么在atomicCAS操作之后,第一个线程将array+idx设置为DEFINED,在该阻塞操作之后,第二个线程将查找array+idx==DEFINED。第二个线程不能保证获得计数值。在CUDA中,我们可以将其编写为一条语句,但编译器会将其分解为多条指令;值=数组[idx];之后仍然需要语句。如果线程读取
D的值