我正在写一个允许两个程序竞争的国际象棋游戏,玩家需要编写一个DLL并公开一个函数来告诉主应用程序这个玩家将在下一个移动的位置,假设该函数看起来像
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 可以正确杀死一个帖子吗?如果没有,我该怎么做才能阻止thead?
答案 0 :(得分:2)
使用Thread.Abort
已经是不好的做法,因为它会在任意点抛出ThreadAbortedException
。它允许执行finally
个子句。因此,如果最终内部存在无限循环,则不会终止该线程。
正确的方法是卸载包含该线程的整个AppDomain
。将每个玩家的dll加载到自己的AppDomain
中。这样你就可以在不破坏主应用程序状态的情况下强制卸载它。
答案 1 :(得分:0)
杀死一个线程是可能的,但这是一种非常糟糕的方法。为什么不让你的玩家为DLL提供“中止”功能?您可以这样做,但将其添加到您的界面。如果玩家捕获ThreadAbortException并且不对它执行任何操作,则中止可能不会停止线程。
答案 2 :(得分:0)
您的代码可能会杀死该主题,但并不是绝对保证。例如,当您尝试杀死的线程重新调出其调用堆栈时,它将执行任何finally块 - 因此您依赖于那些未挂起的代码。因为你的问题似乎暗示线程正在运行的代码将由其他人编写,并且编写它的人可能没有预期尝试中止该线程,所以依靠线程表现良好是不明智的。 (依赖于编写得足够好的代码来清理线程终止之前可能拥有的所有资源,你也是不明智的)
如果你想要一个绝对的100%保证能够杀死正在计算移动的线程,我相信通常的方法是让一个单独的进程主持该线程 - 然后你可以杀死进程。但是,假设您不介意每次需要计算移动时启动新流程所带来的性能损失。