我有一个设置,我需要锁定、读取一些数据、处理、写入一些数据,然后解锁。为此,我制作了一个锁定纹理为 layout(r32ui) coherent uniform uimage2D
.临界区的数据也以类似方式声明。
不幸的是,我对自旋锁的所有尝试都不能防止竞争条件,从而导致不正确的结果。我尝试了几种不同的方法。
我想我会收集我能找到的关于 GLSL 锁定的所有信息,以及我的结果 (GTX 580M)。我在这个详尽的列表中添加了一个社区 Wiki 答案。我将不胜感激对每个提出的可能问题的编辑/评论,最终创建一个有效方法列表。
最佳答案
我已将锁定纹理标准化为 img0
.
锁类型 1:
线程扭曲有一个共享的程序计数器。如果单个线程抢占锁,warp 中的其他线程仍将卡在循环中。实际上,这可以编译但会导致死锁。
示例:StackOverflow , OpenGL.org
while (imageAtomicExchange(img0,coord,1u)==1u);
//<critical section>
memoryBarrier();
imageAtomicExchange(img0,coord,0);
锁类型 2:
要解决类型 1 的问题,可以改为有条件地写入。在下面,我有时将循环编写为 do-while 循环,但 while 循环也无法正常工作。
锁类型 2.1:
尝试的第一件事是一个简单的循环。显然由于错误的优化,这可能会导致崩溃(我最近没有尝试过)。
示例:NVIDIA
bool have_written = false;
while (true) {
bool can_write = (imageAtomicExchange(img0,coord,1u)!=1u);
if (can_write) {
//<critical section>
memoryBarrier();
imageAtomicExchange(img0,coord,0);
break;
}
}
锁类型 2.2:
上面的例子使用
imageAtomicExchange(...)
,这可能不是人们尝试的第一件事。最直观的是imageAtomicCompSwap(...)
.不幸的是,由于错误的优化,这不起作用。它(应该)否则听起来。示例:StackOverflow
bool have_written = false;
do {
bool can_write = (imageAtomicCompSwap(img0,coord,0u,1u)==0u);
if (can_write) {
//<critical section>
memoryBarrier();
imageAtomicExchange(img0,coord,0);
have_written = true;
}
} while (!have_written);
锁类型 2.3:
从
imageAtomicCompSwap(...)
切回至 imageAtomicExchange(...)
是另一个常见的变体。与 2.1 的区别在于循环终止的方式。这对我来说不起作用。示例:StackOverflow , StackOverflow
bool have_written = false;
do {
bool can_write = (imageAtomicExchange(img0,coord,1u)!=1u);
if (can_write) {
//<critical section>
memoryBarrier();
imageAtomicExchange(img0,coord,0);
have_written = true;
}
} while (!have_written);
关于opengl - 损坏的 GLSL Spinlock/GLSL Locks Compendium,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21538555/