继this link,我试着去理解内核代码的工作(有2个版本,这个内核代码,一个与volatile local float *source
和其他与volatile global float *source
,即local
和global
版本)。下面我把local
版本:了解针对OpenCL减少方法上浮动
float sum=0;
void atomic_add_local(volatile local float *source, const float operand) {
union {
unsigned int intVal;
float floatVal;
} newVal;
union {
unsigned int intVal;
float floatVal;
} prevVal;
do {
prevVal.floatVal = *source;
newVal.floatVal = prevVal.floatVal + operand;
} while (atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);
}
如果我没理解好,每个工作项目股份获得source
变量感谢限定词“volatile
”,不是吗?
之后,如果我带一个工作项目,代码会将operand
值添加到newVal.floatVal
变量。然后,在此操作之后,我呼叫atomic_cmpxchg
函数,该函数检查以前的分配(preVal.floatVal = *source;
和newVal.floatVal = prevVal.floatVal + operand;
)是否已完成,即通过将存储在地址source
的值与preVal.intVal
进行比较。
在该原子操作(这是不被定义不间断),为存储在source
值是从prevVal.intVal
不同,储存在source
新值newVal.intVal
,这实际上是一个浮子(因为它是在4个字节等编码整数)。
我们可以说,每个工作项目都有一个互斥体访问(我的意思是一个锁定访问)的价值位于source address
。
但是对于each work-item
线程,是否只有一个迭代进入while loop
?
我想会有一个迭代,因为比较“*source== prevVal.int ? newVal.intVal : newVal.intVal
”将始终将newVal.intVal
值分配给存储在source address
的值,不是吗?
任何帮助都是值得欢迎的,因为我没有理解这个内核代码的所有细节。
更新1:
对不起,我几乎了解所有的subtilities,尤其是在while loop
:
第一种情况:对于给定的单线程,atomic_cmpxchg的调用之前,如果prevVal.floatVal
仍然等于*source
,则atomic_cmpxchg
将更改指针中source
中包含的值并返回包含在old pointer
中的值,这等于prevVal.intVal
,所以我们从while loop
。
第二种情况:如果prevVal.floatVal = *source;
指令和atomic_cmpxchg
呼叫之间,该值已*source
(由另一个线程??)改变,则返回atomic_cmpxchg值old
它是没有到prevVal.floatVal
更多相等,所以该条件成while loop
是真的,我们留在这个循环中,直到之前的条件不再被检查。
我的解释是否正确?
感谢
对不起,如果这对你来说很明显(我想我还没有完全理解这个问题),但是...... while循环是实现原子性的一种标准方式,例如https://en.wikipedia。 org/wiki /比较和交换 – Marco13
这是Marco提到的经典比较交换循环。为了清楚起见,忽略联合技巧,他们只是在这里进行类型双关。另外,如果你有OpenCL 2+,那么浮点数就有内建原子。 –
:Marco13,:Aldwin好的,谢谢。让我们用一个简单的例子来说明两个线程。如果第一个在while循环中,那么,直到第二个修改“prevVal.floatVal”的值,while循环持续第一个线程,不是吗?但是在这种情况下,增量操作“prevVal.floatVal + operand;”是无限的(直到第二个线程停止它),因此存储在地址“source”的值非常高,因为我用大量的“操作数”值进行求和。问候 – youpilat13