怎么让线程互斥修改常量存储的值

  • 6 replies
  • 37358 views
怎么让线程互斥修改常量存储的值
« 于: 三月 15, 2019, 12:55:14 pm »
定义了一个结构体常量数组,现在要对其中的某个参数(如自增变量判断并修改)进行线程互斥读写修改,保证下一个线程读取上一个线程修改过的值而不冲突,应该怎么实现
« 最后编辑时间: 三月 15, 2019, 01:00:57 pm 作者 wcuder »

Re: 怎么让线程互斥修改常量存储的值
« 回复 #1 于: 三月 15, 2019, 01:17:58 pm »
定义了一个结构体常量数组,现在要对其中的某个参数(如自增变量判断并修改)进行线程互斥读写修改,保证下一个线程读取上一个线程修改过的值而不冲突,应该怎么实现

如果你的常量存储指的是__constant__, 则这个做不到(最多只能做到上一个kernel修改,下一个kernel能安全的生效访问)。

如果是其他类型的非local中的数据, 互斥可以做到,可以直接通过内置的原子操作,但无法保证本kernel的线程间的顺序(即:不存在特定的下一个线程之类的概念的)。

建议楼主先看一下原子操作,看看问题能否被修改为适合使用它们。

Re: 怎么让线程互斥修改常量存储的值
« 回复 #2 于: 三月 15, 2019, 01:26:18 pm »
是__constant__类型的,想修改其中某个变量的累计值,用原子操作实现其互斥访问,最后结果不对,所以想问问有什么方法比较好

Re: 怎么让线程互斥修改常量存储的值
« 回复 #3 于: 三月 15, 2019, 02:02:25 pm »
(1)任何时候均不推荐对__constant__中的改写(包括常规写入和原子操作)+ 常规读取混合操作,这将导致未定义的读取值。(因为constant cache在本次kernel启动内,不维持和这些方式写入的一致性)。

(2)唯一接近的方式是,对__constant__全程使用原子操作进行改写+读取(例如,尝试一次原子操作增加0值并返回旧值)。

(3)但这样就失去了constant的意义,和直接使用普通显存或者__device__指针无区别了。

建议的解决方案:
(A)尝试能否本次改写,下次kernel启动读取,这也是常规做法,这样才可能发挥__constant__的效果。
(B)完全放弃__constant__使用普通存储。


Re: 怎么让线程互斥修改常量存储的值
« 回复 #4 于: 三月 15, 2019, 02:12:17 pm »
刚才已改为如您建议的第二种方案,对一个普通变量进行互斥修改,但结果也不对,未能正确输出最后自增的总数,锁模块内的操作流程简单概括是这样:if(i<N){
lock();
a【i】=b;
i++;
unlock();
}
« 最后编辑时间: 三月 15, 2019, 02:18:42 pm 作者 wcuder »

Re: 怎么让线程互斥修改常量存储的值
« 回复 #5 于: 三月 15, 2019, 06:28:50 pm »
刚才已改为如您建议的第二种方案,对一个普通变量进行互斥修改,但结果也不对,未能正确输出最后自增的总数,锁模块内的操作流程简单概括是这样:if(i<N){
lock();
a【i】=b;
i++;
unlock();
}

请您使用CUDA的提供的原子操作,不要使用任何第三方的锁实现(lock/unlock)。
例如:
int pos = atomicAdd(&i, 1);
a[pos] = b;

请注意并非所有的数据类型都支持。

Re: 怎么让线程互斥修改常量存储的值
« 回复 #6 于: 二月 13, 2020, 01:25:46 pm »
atomicAdd()
在60计算能力之后可以进行双精度数据原子操作。