【发布时间】:2017-02-02 13:56:04
【问题描述】:
在this link之后,我尝试了解内核代码的操作(这个内核代码有两个版本,一个是volatile local float *source,另一个是volatile global float *source,即local和global版本) .下面我取local版本:
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);
}
如果我理解得很好,由于限定符“volatile”,每个工作项共享对source 变量的访问权限,不是吗?
之后,如果我接受一个工作项,代码会将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:
对不起,我几乎了解所有的细微之处,尤其是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循环是实现原子性的标准方法,截至en.wikipedia.org/wiki/Compare-and-swap -
:Marco13, :Aldwin 好的,谢谢。让我们看一个有 2 个线程的简单案例。如果第一个在 while 循环中,那么,直到第二个修改“prevVal.floatVal”的值,while 循环才会持续到第一个线程,不是吗?但在这种情况下,递增操作“prevVal.floatVal + 操作数;”是无限的(直到第二个线程停止它),所以存储在地址“源”的值非常高,因为我用大量的“操作数”值求和。问候