2012-02-25 60 views
1

我正在開發一款Android遊戲,並且有一個奇怪的問題,偶爾遊戲會在彈回生命之前變得無響應很長一段時間。據我所知,這種停頓,如果它發生,只會在遊戲啓動時發生。一旦正常運行,遊戲似乎表現自己。即使其他線程沒有鎖定,也需要等待同步對象

經過一番調查後,似乎onTouchEvent回調正在被阻止,試圖獲取它與遊戲線程共享的同步對象的鎖定。同時遊戲線程正常運行,並且不會長時間保持對同步對象的鎖定。

這是我的理解是,doTouchEvent中的同步塊會在遊戲線程釋放該鎖後立即獲取mSyncObject上的鎖。但在某些情況下,似乎遊戲線程能夠在doTouchEvent最終能夠獲取鎖之前獲得並釋放數百次鎖。

沒有其他代碼使用同一個對象進行同步。

我已經複製了以下代碼的相關位。從我能收集到的信息來看,這並不是什麼不尋常的事情,所以我對我所看到的奇怪行爲感到有些莫名其妙。

希望對此有幫助。提前致謝!

class GameThread extends Thread { 

// ...some methods and members omitted... 

private volatile int mFrameCount = 0; 
private Object mSyncObject = new Object(); 

@Override 
public void run() { 
    while (!mShutDown) { 
     Canvas canvas = null; 
     long timestampA = System.currentTimeMillis(); 
     try { 
      synchronized (mSurfaceHolder) { 
       canvas = mSurfaceHolder.lockCanvas(null); 
       // Synchronized on our object... 
       synchronized (mSyncObject) { 
        long now = System.currentTimeMillis(); 
        if ((now > mLastTime) && !mPaused) { 
         double timestep = (double) (now - mLastTime)/1000.0; 
         mGame.update(timestep); 
        } 
        mLastTime = now; 
        if (canvas != null) { 
         mGame.draw(canvas); 
        } 
       } 
      } 
     } finally { 
      if (canvas != null) { 
       mSurfaceHolder.unlockCanvasAndPost(canvas); 
      } 
     } 

     // have tried inserting a sleep() here, but it didn’t help 

     ++mFrameCount; 
    } 
} 


// Called from the UI thread 
public boolean doTouchEvent(MotionEvent event) { 
    boolean result = false; 

    // Synchronized on our object... 
    // The game loop in run() acquires and releases a lock 
    // on this object on every frame, so would expect to be 
    // blocked here for no longer than one frame. 
    // However, on occasions have been blocked here for over 
    // 2000 iterations of the game loop. 
    int frameCount = mFrameCount; 
    synchronized (mSyncObject) { 
     int framesWaited = mFrameCount - frameCount; 
     if (framesWaited > 1) { 
      Log.i("Block", "doTouchEvent waited " + framesWaited + " frames for lock"); 
     } 

     if (!(mPaused || mShutDown)) { 
      result = mGame.doTouchEvent(event); 
     } 
    } 
    return result; 
} 

} 

回答

1

看來這個問題是由於同步提供的公平性並不能保證等待線程獲得鎖的順序。事實上,如果另一個cpu密集型線程反覆獲取並釋放鎖,則線程可以無限期地等待鎖定。

看到這個主題討論一模一樣的問題......

http://groups.google.com/group/android-developers/browse_frm/thread/ffe76e4a433c8675/f424fb7dc3baeb10

...這裏的一個線程安全的,但無同步解決方案的例子。

http://blog.tomgibara.com/post/208684592/avoiding-starvation

之前在上面的絆腳石,我改變了我的代碼通過使用的ConcurrentLinkedQueue,這似乎也有效地消除了攤位線程之間的運動賽事。

0

..您正在爲遊戲循環的每個循環獲取3個不同的鎖!你必須想到一個更好的設計,你不需要鎖。這會使您的遊戲性能下降。

+0

起初,我已經在mSurfaceHolder上同步所有內容,但爲doTouchEvent添加了單獨的同步對象,以減少可能被阻止的數量(儘管不是太多)。 – threeshinyapples 2012-02-25 20:26:33

+0

對不起,提交得太快,無法編輯,因爲太多的時間過去... 我意識到最好的解決方案將涉及到一個輕微的重新設計,以確保觸摸事件可以安全地處理,而不依賴於同步。 但我真的很想知道爲什麼我看到這種情況,UI線程似乎無法獲得它的同步鎖定很長一段時間,即使遊戲線程給了它大量的機會。 – threeshinyapples 2012-02-25 20:34:27