老问题:如何立即杀死一个线程在c#

问题描述:

我正在写一个国际象棋游戏,它允许两个程序竞争,玩家需要写一个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正确地杀死一个线程?如果不是的话,我应该怎么做才能阻止他们?

使用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

杀死一个线程是可能的,但是一个非常糟糕的方法。为什么不要让你的玩家向DLL提供一个“中止”函数?你可以做,但将其添加到你的界面。如果播放器捕获到ThreadAbortException并且不执行任何操作,Abort可能不会停止一个线程。

+0

'catch'块退出后重新抛出异常。所以他不能像其他例外那样捕捉它。但是,当然如果'catch' /'finally'块没有退出线程将不会终止。 – CodesInChaos 2011-03-09 09:19:54

+0

为什么不只是要求你的玩家向DLL提供一个“中止”函数呢? ----假设玩家的函数'MoveNext'中有一个无限循环,那么玩家提供的'Abort'函数如何退出? – 2011-03-10 05:32:44

你的代码可能会杀死线程,但并不是绝对的保证。例如,当你试图杀死的线程回滚它的调用堆栈时,它会执行任何最后的块 - 所以你依赖那些不挂起的代码。因为你的问题似乎意味着线程正在运行的代码将由其他人编写,编写它的人可能没有预料到会中止线程的尝试,所以依靠线程的行为是不明智的。 (你也不明智的依靠编写的代码来清理它在线程终止前可能拥有的所有资源)

如果你想绝对100%保证能够杀死正在计算的线程此举,我相信通常的方法是让一个单独的进程托管该线程 - 然后您可以终止进程。但是,这假定您不介意每次需要计算移动时开始新进程时的性能影响。