2011-10-15 143 views
1

我目前(嘗試)編程一個小遊戲。我有一個小設計/死鎖問題。殺死僵局

當我按下一個按鈕時,一個新的Intent打開並且surfaceDestroyed設置一個布爾值來設置睡眠線程。 當我返回線程獲取通知信號。

這可以在大約90%的時間內完成(當我使用eclipse進行調試時,這是100%)。

我相信死鎖發生在線程的運行功能(兩個同步)。問題是,wait()需要一個同步的線程,而ondraw()需要對這個表面持有者進行鎖定。

我已經玩過一段時間了,但所有其他組合都會讓事情變得更糟,我不知道如何解決這個問題。所以,請幫助:)

的主題:

class BattleEarthThread extends Thread { 
    private SurfaceHolder _surfaceHolder; 
    private BattleEarthView _battleEarthView; 
    private boolean _run = false; 
    private boolean _suspended = false; 

    public SurfaceHolder getSurfaceHolder() { 
     return _surfaceHolder; 
    } 

    public BattleEarthThread(SurfaceHolder surfaceHolder, BattleEarthView panel) { 
     _surfaceHolder = surfaceHolder; 
     _battleEarthView = panel; 
    } 

    public void setRunning(boolean run) { 
     _run = run; 
    } 

    public void setSuspend(boolean suspend) { 
     _suspended = suspend; 
    } 

    public boolean getSuspended() { 
     return _run; 
    } 

    public boolean getRunning() { 
     return _run; 
    } 

    @Override 
    public void start() { 
     super.start(); 
     _run = true; 
    } 

    @Override 
    public void run() { 
     Canvas c; 
     while (_run) { 
      c = null; 
      try { 
       synchronized(this) 
       { 
         c = _surfaceHolder.lockCanvas(null); 
         synchronized (_surfaceHolder) { 

          if(_suspended) 
           this.wait(); 

          else { 
           _battleEarthView.onDraw(c); 
          } 
         } 
        } 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } finally { 
       if (c != null) { 
        _surfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 
     } 
    } 
} 
+0

我們需要查看其他線程的代碼才能完全理解這一點。 – Delyan

回答

3

這就是問題所在:

synchronized(this) { 
    c = _surfaceHolder.lockCanvas(null); 
    synchronized (_surfaceHolder) { 

     if(_suspended) 
      this.wait(); 

     else { 
      _battleEarthView.onDraw(c); 
     } 
    } 
} 

你取出兩把鎖 - this_surfaceHolder。您然後通過撥打wait釋放this ...但您仍然擁有鎖_surfaceHolder

現在假設另一個線程在同一個對象上執行相同的代碼。它設法獲取this的鎖定,因爲目前沒有其他東西擁有它,但它在嘗試獲取_surfaceHolder時阻止,因爲等待線程擁有它。

在這一點上,你釀:

  • 沒有線程才能獲取該對象的鎖正在等待上,因爲第二個線程擁有它
  • 即使另一個線程可能脈衝鎖,等待線程仍然需要繼續,它將無法

所以基本上你有兩個線程,每個擁有一個LOC之前重新獲得對this鎖k並正在等待不可能發生的事情。這不是相當於正常的死鎖(每個線程擁有一個鎖並且正在等待另一個鎖),但它非常接近。

道德:不要在當前「擁有」更多顯示器的線程上調用wait(),因爲它將調用wait()

+0

我認爲是這樣,但如何擺脫這個問題?通知需要線程上的鎖定提取需要的水頭? – Vulcano

+0

@ user989349:說實話,你不明白你想達到什麼目的。但是eek--我沒有看到你鎖定了* thread *引用。首先,不要擴展Thread - 實現Runnable。其次,不要獲取線程上的鎖定或等待它。其他事情是這樣做的,所以最好不要自己去做。什麼是脈衝鎖,而且它可以脈衝'_surfaceHolder'來代替? –

+0

澄清事情:我有一個地圖,當我點擊一個城鎮,我想建立一些東西。當我離開城鎮時,地圖應該再次顯示。所以地圖繪製的第一部分是來自LunarLander(也有一個線程),第二部分來自Oracle(搜索threadPrimitiveDeprecation :)) – Vulcano