2011-03-09 140 views
1

我正在寫一個國際象棋遊戲,它允許兩個程序競爭,玩家需要寫一個DLL並公開一個函數來告訴主應用程序這個玩家將在下一步移動,假設函數看起來像老問題:如何立即殺死一個線程在c#

public static void MoveNext(out int x, out int y, out int discKind); 

在象棋遊戲應用時,我開始一個新的線程來調用播放器的DLL暴露得在那裏他將在轉彎移動的功能,我開始一個計時器,以防止玩家超時

private Thread mPlayerMoveThread; 

private void SetPlayerToMove(IPlayer player) 
     { 
      this.CurrentPlayer = player; 

      try 
      { 

        System.Threading.Timer mTimeoutTimer = 
            new Timer(new TimerCallback(TimeIsUp), 
            null, 
            this.mMaxTimeOfOnePlayer, 
            Timeout.Infinite); 

        mPlayerMoveThread = new Thread(this.ThreadMethodPlayerAction); 
        mPlayerMoveThread.IsBackground = true; 
        mPlayerMoveThread.Start(); 
      } 
      catch(Exception ex) 
      { 
       //// invalid move, so finish the game 
       HandleInvalidMove(player.Color, ex); 
      } 
     } 

private void ThreadMethodPlayerAction() 
     { 
      this.CurrentPlayer.MoveNext(); 
     } 

     private void KillThread(Thread thread) 
     { 
      if (thread == null || thread.ThreadState == ThreadState.Stopped) 
       return; 

      try 
      { 
       thread.Abort(); 
       thread.Join(); 
      } 
      catch 
      { 
      } 
      finally 
      { 
       thread = null; 
      } 

     } 

     private void TimeIsUp(object state) 
     { 
      // kill the threads 
      KillThread(mPlayerMoveThread); 

      HandleInvalidMove(this.CurrentPlayer.Color, new Exception("timeout")); 
     } 

我的問題是: 我的功能KillThread正確地殺死一個線程?如果不是的話,我應該怎麼做才能阻止他們?

回答

2

使用Thread.Abort已經是不好的做法,因爲它會在任意點處拋出ThreadAbortedException。它允許finally子句執行。因此,如果終端內有無限循環,它不會終止該線程。

正確的方法是卸載包含該線程的整個AppDomain。將每個玩家的dll加入自己的AppDomain。這樣,您可以在不破壞主應用程序狀態的情況下強制卸載它。

+0

我喜歡'AppDomain'的想法,你會給我一些簡單的代碼來說明如何做到這一點? – 2011-03-10 05:31:09

+0

我還沒有和他們合作過。但是'Hosting'和'AppDomain'應該給出一些搜索結果。如果您需要沙盒,我建議您查看.net 4模型,它比舊模型更容易。 – CodesInChaos 2011-03-10 08:37:53

0

殺死一個線程是可能的,但是一個非常糟糕的方法。爲什麼不要讓你的玩家向DLL提供一個「中止」函數?你可以做,但將其添加到你的界面。如果播放器捕獲到ThreadAbortException並且不執行任何操作,Abort可能不會停止一個線程。

+0

'catch'塊退出後重新拋出異常。所以他不能像其他例外那樣捕捉它。但是,當然如果'catch' /'finally'塊沒有退出線程將不會終止。 – CodesInChaos 2011-03-09 09:19:54

+0

爲什麼不只是要求你的玩家向DLL提供一個「中止」函數呢? ----假設玩家的函數'MoveNext'中有一個無限循環,那麼玩家提供的'Abort'函數如何退出? – 2011-03-10 05:32:44

0

你的代碼可能會殺死線程,但並不是絕對的保證。例如,當你試圖殺死的線程回滾它的調用堆棧時,它會執行任何最後的塊 - 所以你依賴那些不掛起的代碼。因爲你的問題似乎意味着線程正在運行的代碼將由其他人編寫,編寫它的人可能沒有預料到會中止線程的嘗試,所以依靠線程的行爲是不明智的。 (你也不明智的依靠編寫的代碼來清理它在線程終止前可能擁有的所有資源)

如果你想絕對100%保證能夠殺死正在計算的線程此舉,我相信通常的方法是讓一個單獨的進程託管該線程 - 然後您可以終止進程。但是,這假定您不介意每次需要計算移動時開始新進程時的性能影響。