我是C#线程的新手,尽管阅读了很多关于线程的理论,但它在实践中对我没什么帮助。
我想为棋子游戏编写AI函数(minmax alphabeta)并在不同的线程中执行它。
有4种选择:常规线程,线程池,异步委托,BackgroundWorker。
BackgroundWorker在我看来是理想的,它有委托完成所以我可以运行“makemove”函数,它实际上会在板上进行计算移动并更新进度条。
我有3个问题:
对于这种情况,BackgroundWorker真的是最好的解决方案吗?
BackgroundWorker在线程池中执行,有什么好处?当你有许多不同的线程时,总是说线程池是好的,这不是我的情况。
我看到的所有代码示例都过于简单,并展示了如何创建一个这样的线程。在我的程序中,我需要在计算机每次运行时运行此函数,所以我可能需要杀死前一个线程并启动一个新线程。实现这一切的正确方法是什么?
任何帮助都将不胜感激。
答案 0 :(得分:3)
1)任何和所有这些解决方案都可行;你只需要使用一些不同的逻辑来处理每一个。
2)当你有一组可以在多个线程上执行的东西时,ThreadPool也很有用(例如,在中国跳棋游戏中,你可以通过ThreadPool运行5种不同的AI模拟,它可以在计算机上以最佳方式运行它有两个内核,而使用Threads会因为上下文切换而减慢进程速度)。它肯定适用于您的情况 - 您只需排队第二次AIEvaluation或其他什么,它会尽快开始执行。
3)嗯,不是真的。计算机在运行alphabeta之后才能真正移动(大概有一些截止深度:P)所以AI线程无论如何都会完成它的工作。你每次都可以使用ThreadPool / BackgroundWorker。
关于BackgroundWorker的一些一般信息:它在你有“额外”的CPU时间时运行,所以如果你的主线程由于某种原因而占用CPU,它将不会做很多事情。使用普通的ThreadPool可能更好。
假设你的程序在主线程上启用了AI,你的程序会调用AIAct()。另外,让timerTick成为Windows窗体中存在的排序的计时器。此外,还有AIState和GameBoard类,它们封装了alpha-beta所需的功能。
using System.Threading;
const int CUTOFF_DEPTH = 6;//Maximum plys for alpha-beta
AIState state;
void AIAct()
{
state = new AIState( this.GameBoard.GetState() );
ThreadPool.QueueUserWorkItem(RunMinimax, state);
//assume that timerTick is a Timer (Windows Forms Timer) that ticks every 100 ms
timerTick.Enabled = true;
}
void timerTick_Tick(object sender, EventArgs e)
{
if (state.IsComplete)
{
ExecuteAction(state.Result);
timerTick.Enabled = false;
//whatever else you need to do
}
}
private static void RunMinimax(object args)
{
AIState state = args as AIState;
if (state == null)
{
//error handling of some sort
Thread.CurrentThread.Abort();
}
//run your minimax function up to max depth of CUTOFF_DEPTH
state.Result = Minimax( /* */ );
state.IsComplete = true;
}
private class AIState
{
public AIState(GameBoard board)
{
this.Board = board;
}
public readonly GameBoard Board;
public AIAction Result;
public volatile bool IsComplete;
}