我的@synchronized块出了什么问题?

时间:2010-05-16 19:05:17

标签: iphone objective-c cocoa-touch multithreading nsthread

我的应用程序中有2个线程,一个游戏更新线程和渲染/ IO /主线程。 我的更新线程更新游戏状态,渲染线程根据游戏状态模型的更新值和存储在对象(gameEngine)中的一些其他变量来渲染场景。

渲染线程在游戏线程仍在更新时执行,这是一个问题,所以在我看来解决方案是使用@synchronized这样:

        @synchronized(gameEngine)
        {
            [gameEngine update];

            nextUpdate = now + GAME_UPDATE_INTERVAL;

            gameEngine.lastGameUpdateInterval = now - lastUpdate;
            gameEngine.lastGameUpdateTime = now;
            lastUpdate = now;
        }

但是渲染线程仍然访问-update和块的最后3行之间的gameEngine对象。这是为什么?

2 个答案:

答案 0 :(得分:10)

@synchronized不会阻止其他线程访问gameEngine。它只是阻止具有相同对象的其他@synchronized。这意味着在

// thread A:
@synchronized(a) {
   do_A(a);
}
...
// thread B:
do_B(a);

do_Ado_B可以一起发生,但在

// thread A:
@synchronized(a) {
   do_A(a);
}
...
// thread B:
@syncrhonized(a) {
   do_B(a);
}

do_Ado_B将始终按顺序执行。

答案 1 :(得分:0)

你不应该锁定gameEngine - @KennyTM解释了我认为对你的问题的正确答案,但是实现它会导致游戏引擎或渲染器只能在给定时间执行,使它基本上是单线程的。你应该做的是使用一个不可变的状态对象,它可能是gameEngine的ivar,但应该是非原子的,在render函数中你可以像这样获取状态

State *state = [[gameEngine state] retain];

然后使用state,完成后释放它。当gameEngine执行更新时,它不应该改变其状态ivar中的数据,这可能是渲染器使用的,但可以复制它。要设置状态,它应该

State *oldState = state;
state = newState; //newState should have a retainCount of 1
[oldState release];

因为如果在将状态设置为newState之前释放oldState,那么渲染器可能会获得oldState,它刚刚被释放,导致Bad Things。