游戏引擎中执行安全状态更改的策略是什么?

时间:2012-05-17 15:32:35

标签: iphone ios multithreading opengl-es concurrency

我在OpenGL ES中创建了一个运行循环,由CADisplayLink以60fps调用。 AFAIK CADisplayLink在后台线程上调用它的目标。

我有大约100个运行循环使用的状态变量。

问题:从主线程,我想更改运行循环中使用的状态变量来绘制一些东西。只有在所有状态变量都设置为目标值后才能绘制框架。

我担心在某些时候,当我更改状态变量时,我还没有更改它们(在主线程上的相同运行循环迭代中的一个大方法),例如几何形状的位置,存在多线程相关的崩溃或问题,其中CADisplayLink将在我的方法中间启动,更新状态变量,然后绘制垃圾或崩溃。

显然,当我只使用同步或原子属性时,它无济于事,因为它仍然不是事务性的。我想我需要交易。

我天真的做法是:

运行循环读取的实例变量:

BOOL updatingState;

如果updatesState为YES,则运行循环方法将跳过绘图。

然后在开始改变状态之前,我将其设置为YES。当一切都改变了,我把它重新设置为NO。

现在当然,问题:如果 - 我正在改变这一点 - 运行循环方法正在读取值?

游戏引擎如何处理这个问题?它们具有什么样的锁定机制,因此可以在绘制下一帧之前完成状态变量的更改?

3 个答案:

答案 0 :(得分:2)

您可能会发现有用的读取 - 复制 - 更新策略。一种可能的实现是每个对象实际上包含两个呈现参数副本,并且原子标志用于告知呈现线程使用哪个。您需要在渲染器中使用读取内存屏障,以确保在读取任何参数之前读取该标志,并在更新程序线程中写入内存屏障,以确保在翻转标志之前写入所有参数更新

答案 1 :(得分:1)

通常的方法是在绘制完成之前,所有状态更新都发生在每次运行循环迭代中。也就是说,运行循环看起来像这样:

updateState();
draw();

使用此模型,绘图仅在达到一致状态后才会发生。

为了实现这一点,你需要有一个模型,在每个updateState()上轮询事件,例如按键,而不是异步发生,以及每次迭代的时间测量,告诉你自上次以来经过了多少时间帧。

我无法帮助你在iOS编程的具体情况下如何实现这一点,因为我对此一无所知。但我希望我能指出你正确的方向。

答案 2 :(得分:1)

我认为这是并发中的常见问题,因此有几种方法可以做到:

  1. 使用不可变状态类来保存状态变量。
  2. 使用锁定机制(如果不能使用不可变类)来保护状态变量。
  3. 您可以修改多个状态,但只有一个状态为“活动状态”。这将允许您重用状态,这将减少复制和内存分配。
  4. 此外,请考虑以下情况:

    线程1.开始画画。
    线程1.读取状态01参数的1/2(第一状态) 线程2.用状态02(第二状态)交换状态01 线程1.读取状态02的另一个1/2,但它与状态01参数不同。

    因此,最好的选择是不允许在绘图期间更新状态,因此选项3可能是最好的方法,因为您只需获取最新状态并绘制它。假设您有两种状态:drawingStatenonDrawingState。在绘图功能中,您将始终使用drawingState绘制,而其他线程则修改nonDrawingState。完成绘图后,您可以交换状态并继续绘制最新的状态修改。