2010-05-16 50 views
2

我在我的應用程序中有2個線程,一個遊戲更新線程和渲染/ IO /主線程。 我的更新線程更新遊戲狀態,並且呈現線程根據遊戲狀態模型的更新值以及存儲在對象(gameEngine)中的一些其他變量呈現場景。我的@synchronized塊有什麼問題?

渲染線程而遊戲線程仍在更新,這是一個問題得到執行,所以在我看來,解決辦法是使用@Synchronized這樣的:

 @synchronized(gameEngine) 
     { 
      [gameEngine update]; 

      nextUpdate = now + GAME_UPDATE_INTERVAL; 

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

但渲染線程仍然訪問-update與該塊的最後3行之間的gameEngine對象。爲什麼是這樣?

+0

請顯示您期望在渲染線程上執行的代碼。它是否也在同一個gameEngine對象的@synchronize塊中? – Ken 2010-05-16 19:09:37

回答

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總是會順序執行。

+0

這正是我正在做的和我需要做的事情來解決它。 – Morrowless 2010-05-17 03:36:07

+0

這是一個很好的答案,對我很有幫助,謝謝。 – krafter 2011-12-09 09:58:22

0

您不應該鎖定gameEngine - @KennyTM解釋了我相信您的問題的正確答案,但實現它只會導致遊戲引擎或渲染器能夠在給定時間執行,使它基本上是單線程的。你應該用一個不變的狀態對象,這可能是gameEngine的伊娃做,而應該是非原子,其中在渲染功能,你搶,像這樣

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

,然後使用狀態的狀態,完成後釋放它。當gameEngine執行更新時,它不應該改變處於狀態ivar的數據,這可能會被渲染器使用,但可能會複製它。要設置狀態,它應該

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

,因爲如果你設置狀態newState然後渲染可能會得到原狀態數,這是剛剛釋放,導致糟糕事情之前釋放原狀態數。

+0

-1,你有一個競爭條件,可能導致渲染器引用一個釋放對象。 '[[gameEngine state] retain]'不是原子的。如果渲染器在從'gameEngine狀態'返回之後但在發送保留之前被中斷,並且遊戲引擎被允許完全更新狀態,包括'[oldState release]'在渲染器被計劃執行保留之前,則該對象可以被解除分配。 – JeremyP 2010-05-17 09:29:40

+0

他實現你想要的東西的安全方法是使'-state'成爲一個原子屬性。這導致一小部分同步代碼,但單線程部分實際上限於發送保留和自動釋放到伊娃的時間。 – JeremyP 2010-05-17 09:30:35

+0

即使狀態是原子狀態,這隻意味着 - [gameEngine狀態]將返回一個有效的引用,但在調用retain之前可能會消失。這並不是說我是對的 - 遠非如此,謝謝你提出我的競爭條件,但由於狀態設置的方式, - [gameEngine狀態]保證總是保留至少一個。 – 2010-05-17 19:04:30