1

我正在尝试同步一对非 UI 线程,一个线程运行游戏逻辑,一个线程渲染,以便以逻辑和有效的顺序执行任务。我自己强加的一个约束是整个系统在无分配的稳定状态下运行,因此所有显示对象都被返回并“回收”,因此两个线程必须保持一种双向对话,当我调用'swapBuffers()' 方法。

在伪代码中,游戏线程中的事件顺序如下所示:

while(condition)
{
    processUserInput();
    runGameLogicCycle(set number of times);

    waitForBuffersSwapped();

    unloadRecycleBuffer();  //This function modifies one buffer
    loadDisplayBuffer();    ///This function modifies another buffer

    waitForRenderFinished();

    renderThread.postTask(swapBuffersAndRender);
}

选择渲染线程来执行交换缓冲区的任务,以便游戏逻辑线程可以同时执行不修改缓冲区的任务。在我的代码中,我结合了交换缓冲区和渲染的任务,并将其定义为一个 Runnable 对象,该对象发布到渲染线程的处理程序。在伪代码中,该可运行文件如下所示:

{
    //Swap the buffers
}
gameThread.notifyThatBuffersSwapped();
{
    //Render items to screen
}
gameThread.notifyThatItemsRendered();

我的问题是实施问题。我熟悉处理程序、同步块和 ReentrantLocks 的概念。我知道 Lock.await() Lock.signal() 方法,但是当我试图了解它们在迭代循环中调用时的行为时,我发现文档不足。

如何实现 ReentrantLocks 以使两个线程以这种方式相互等待?如果可能,请在您的答案中包含一个实用的成语。

4

1 回答 1

1

我不确定 Lock 是你想要的。您确实希望当前线程对对象具有独占访问权,但是一旦您释放锁,您希望确保在再次获得锁之前另一个线程能够执行。

例如,您可以使用名称不佳的ConditionVariable

loop:
game thread: does stuff w/objects
game thread: cv1.close()
game thread: cv2.open()
[render thread now "owns" the objects]
game thread: does stuff w/o objects
game thread: cv1.block()
game thread: [blocks]

loop:
render thread: does stuff w/objects
render thread: cv2.close()
render thread: cv1.open()
[game thread now "owns" the objects]
render thread: cv2.block()
render thread: [blocks]

这将同步操作两个线程。在对非共享对象进行操作时,您会获得一些并发性,仅此而已。

java.util.concurrent提供CountDownLatch,但这是一次性对象,这违背了您避免分配的愿望。幻想CyclicBarrier做得更多。

这不是一个很好的解决方案——虽然锁并不是你想要的,但它们是你想要的一部分,我在这里取消了它们。查看代码并轻松确定两个线程不能同时对对象进行操作是不可能的。

您可能需要考虑对对象进行双重缓冲。您需要两倍的内存,但同步问题更简单:每个线程本质上都有自己的数据集要处理,唯一需要暂停的时间是游戏线程想要交换集时。并发性最大化。如果游戏线程迟到了,渲染线程只会再次绘制它所拥有的内容(如果您正在使用 a GLSurfaceView)或跳过渲染。(您可以对整个事情进行花哨的三重缓冲以提高吞吐量,但这会增加内存使用和延迟。)

于 2013-06-04T21:07:26.123 回答