破碎的GLSL Spinlock / GLSL Locks Compendium

时间:2014-02-03 21:49:59

标签: opengl atomic spinlock

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

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

我以为我会收集有关GLSL锁定的所有信息,以及我的结果(GTX 580M)。我已经在这个详尽的列表中添加了社区Wiki答案。我希望对每个提出的可能问题进行编辑/评论,最终创建一个有效方法列表。

1 个答案:

答案 0 :(得分:5)

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

锁定类型1:

线程warp有一个共享程序计数器。如果单个线程抓取锁定,则warp中的其他线程仍将卡在循环中。在实践中,这会编译但会导致死锁。

示例: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);