Что не так с моим @synchronized блоком? - PullRequest
2 голосов
/ 16 мая 2010

В моем приложении 2 потока, поток обновления игры и поток рендеринга / ввода-вывода / основного потока. Мой поток обновлений обновляет состояние игры, а поток рендеринга визуализирует сцену на основе обновленных значений моделей состояния игры и нескольких других переменных, хранящихся внутри объекта (gameEngine).

Поток рендеринга выполняется во время обновления игрового потока, что является проблемой, поэтому мне показалось, что решение заключается в использовании @synchronized следующим образом:

        @synchronized(gameEngine)
        {
            [gameEngine update];

            nextUpdate = now + GAME_UPDATE_INTERVAL;

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

Но поток рендеринга по-прежнему обращается к объекту gameEngine между -update и последними 3 строками блока. Почему это?

Ответы [ 2 ]

10 голосов
/ 16 мая 2010

@synchronized не блокирует доступ других потоков к gameEngine. Он просто блокирует другие @synchronized тем же объектом. Это значит в

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

do_A и do_B могут происходить вместе, но в

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

do_A и do_B всегда будут выполняться последовательно.

0 голосов
/ 16 мая 2010

Вы не должны блокировать gameEngine - @KennyTM объяснил, что я считаю правильным ответом на ваш вопрос, однако его реализация привела бы к тому, что только игровой движок или средство визуализации могли выполняться в данный момент времени делая его по существу однопоточным. Вам следует использовать неизменяемый объект состояния, который может быть иваром gameEngine, но должен иметь значение nonatomic , где в функции рендеринга вы захватываете состояние следующим образом

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

и затем используйте состояние, освобождая его, когда закончите. Когда gameEngine выполняет обновление, он не должен изменять данные в своем состоянии ivar, которое может использоваться средством визуализации, но может сделать его копию. Чтобы установить состояние, оно должно

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

потому что если вы отпустите oldState перед установкой состояния newState, то средство визуализации может получить oldState, который был только что освобожден, что приведет к плохим вещам.

...