破碎的GLSL自旋锁/GLSL锁汇编

4

我有一个设置,需要锁定、读取一些数据、处理、写入一些数据,然后解锁。为此,我制作了一个锁定纹理作为layout(r32ui) coherent uniform uimage2D。关键部分的数据也是类似声明的。

不幸的是,我的所有自旋锁尝试都无法防止竞争条件,导致结果不正确。我尝试了几种不同的方法。

我想收集我能找到的关于GLSL锁定的所有信息,以及我的结果(GTX 580M)。我已经添加了一个社区维基答案,其中包含这个详尽的列表。我希望编辑/评论每个可能存在的问题,最终创建一个有效方法的列表。

1个回答

6
我已将锁定纹理标准化为img0

锁类型1:

线程绕组有一个共享的程序计数器。 如果单个线程获取了锁,则在同一绕组中的其他线程仍将被卡在循环中。 在实践中,这样编译可行但会导致死锁。

示例:StackOverflowOpenGL.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的不同之处在于循环的终止方式。但这对我来说并不正确。

示例:StackOverflowStackOverflow

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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接