当我试图找到有关内核中原子操作的更多细节时,我发现有些奇怪的事情。据我所知,当在一个数字上使用原子操作时,所有这些来自所有线程的操作都将被序列化以在此数字上启动以保持完整性。以下是我的内核代码:
if(atomic_cmpxchg(&A[ptr],0,-1) == -1)
ptr = A[ptr + 3];
//To delay
uint k = 1000000;
while(k--);
A[ptr + 3] = newValue;
对于上面的代码,假设只有两个线程T1和T2。据我所知,T1和T2都会执行代码片段,但是当他们尝试执行atomic_cmpxchg操作时,T2必须等待T1完成(假设T1先运行)。正如我设计的那样,当T1读取A [ptr]时,A [ptr]的旧值为0,因此它将原子地改为-1。之后,因为对于T1,条件不满足,所以T1将直接转到延迟代码并被延迟。现在是时候T2在A [ptr]上工作,因为现在A [ptr]已被设置为-1,因此T2的条件满足,因此T2将运行到“ptr = A [ptr + 3];” 。但我的问题是:因为在T2完成条件判断后,它将执行“ptr = A [ptr + 3];”但是,T1会遇到延迟,所以A [ptr + 3]的值还没有被T1更新(因为k太大而且延迟会很长)。所以T2不会读取A [ptr + 3]的最新值,它应该是 newValue 。但是我的实验表明,无论我设置 k 值多大,结果总是正确的,即无论多长时间,T2总能读取正确的值( newValue )延迟T1遇到。任何人都可以帮助调查此案例吗?非常感谢。
答案 0 :(得分:2)
编译器可能很聪明,可以确定你的“延迟”循环没有副作用并完全优化它。
在GPU上,来自同一工作组的OpenCL工作项通常在lock-step中运行(至少在某种程度上,具体取决于具体的硬件)。这意味着两个线程同时执行相同的指令。它们基本上共享指令指针。在发散控制流的情况下,每个线程都记住它当前是否处于活动状态,并且仅在执行当前指令时执行。原子操作仍然是序列化的。