我有一个设置,我需要锁定,读取一些数据,处理,写入一些数据,然后解锁。为此,我将锁定纹理设为layout(r32ui) coherent uniform uimage2D
。关键部分的数据声明类似。
不幸的是,我对螺旋锁的所有尝试都没有阻止竞争条件,导致不正确的结果。我尝试了几种不同的方法。
我以为我会收集有关GLSL锁定的所有信息,以及我的结果(GTX 580M)。我已经在这个详尽的列表中添加了社区Wiki答案。我希望对每个提出的可能问题进行编辑/评论,最终创建一个有效方法列表。
答案 0 :(得分:5)
我已将锁定纹理标准化为img0
。
线程warp有一个共享程序计数器。如果单个线程抓取锁定,则warp中的其他线程仍将卡在循环中。在实践中,这会编译但会导致死锁。
while (imageAtomicExchange(img0,coord,1u)==1u);
//<critical section>
memoryBarrier();
imageAtomicExchange(img0,coord,0);
要解决类型1的问题,请改为有条件地写入。在下面,我有时将循环写为do-while循环,但while循环也无法正常工作。
首先尝试的是一个简单的循环。显然由于错误的优化,这可能导致崩溃(我最近没有尝试过)。
示例: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;
}
}
上面的示例使用了imageAtomicExchange(...)
,这可能不是人们尝试的第一件事。最直观的是imageAtomicCompSwap(...)
。不幸的是,由于错误的优化,这不起作用。它(应该)另有声音。
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);
从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);