我有一个Game框架,其中有一个实现IBotInterface的Bots列表.这些机器人是由用户定制的,唯一的限制是它们必须实现接口.
然后游戏调用机器人中的方法(希望并行),用于各种事件,如yourTurn和roundStart.我希望机器人在被迫退出计算之前只花费有限的时间来处理这些事件.
我正在尝试的一种例子是:(其中NewGame是代表)
Parallel.ForEach(Bots, delegate(IBot bot) { NewGame del = bot.NewGame; IAsyncResult r = del.BeginInvoke(Info, null, null); WaitHandle h = r.AsyncWaitHandle; h.WaitOne(RoundLimit); if (!r.IsCompleted) { del.EndInvoke(r); } } );
在这种情况下,我被迫运行可能不会终止的EndInvoke().我想不出一种干净地中止线程的方法.
如果有某种形式的话会很棒
try { bot.NewGame(Info); } catch (TimeOutException) { // Tell bot off. } finally { // Compute things. }
但我不认为有可能制作这样的结构.
这样做的目的是优雅地处理具有偶然无限循环或需要很长时间计算的AI.
解决这个问题的另一种可能方法就是拥有这样的东西(更多的c#和更少的伪代码)
Class ActionThread { pulbic Thread thread { get; set; } public Queuequeue { get; set; } public void Run() { while (true) { queue.WaitOne(); Act a = queue.dequeue(); a(); } } Class foo { main() { .... foreach(Bot b in Bots) { ActionThread a = getActionThread(b.UniqueID); NewGame del = b.NewGame; a.queue.queue(del); } Thread.Sleep(1000); foreach (ActionThread a in Threads) { a.Suspend(); } } }
不是最干净的方式,但它会起作用.(我会担心如何传递参数并稍后获取返回值).
[进一步编辑]
我不太确定appdomain是什么,从它的外观我可以这样做,但它无法看到它会如何帮助
我希望不要指望恶意代码.试图杀死其他机器人线程并不是赢得游戏的有效方式.我只想给每个机器人一秒钟进行计算然后继续使用游戏流程,因此主要期望这里的代码速度慢或有问题.
我正试着看看我能用Task做些什么,慢慢来到某个地方.
我会读到CAS可以做什么,谢谢你们
[更多编辑]
我的头疼,我似乎无法思考或编码了.我正在建立一个消息传递系统到每个机器人的专用线程,并将暂停/睡眠这些线程
我已经决定使用完全插座的服务器客户端系统.这样客户端可以做任何想做的事情,如果它拒绝回复服务器消息,我会忽略它.可惜它必须来到这一点.
不幸的是,没有100%安全的方法可以干净地终止线程,就像你想要的那样.
有很多方法可以尝试这样做,但它们都有一些你可能想要考虑的副作用和缺点.
唯一干净,安全且经过批准的方法是获得有问题的线程的合作并很好地问它.但是,如果您控制代码,这只是100%保证的方式.既然你不是,那就不会.
这是问题所在.
如果您执行Thread.Abort,则可能会使appdomain处于不安全状态.可能存在文件未打开,网络或数据库连接未打开,内核对象处于无效状态等.
即使您将线程放入其自己的应用程序域,并在中止该线程后拆除该应用程序域,您也不能100%安全地认为您的进程将来不会出现问题.
让我们来看看为什么合作也不是100%.
假设有问题的线程经常需要调用你的库代码,以便在屏幕上绘图,或者诸如此类的东西.您可以轻松地检查这些方法,并抛出异常.
但是,该异常可能被捕获并被吞噬.
或者有问题的代码可能进入一个无限循环,根本不会调用你的库代码,这会让你回到原点,如何在没有合作的情况下干净地杀死线程.
我已经说过你不能.
但是,有一种方法可行.您可以将机器人生成到自己的进程中,然后在超时时终止该进程.这将为您提供更高的成功机会,因为至少操作系统将在流程终止时处理它管理的所有资源.你当然可以让这个过程在系统上留下损坏的文件,所以再次,它不是100%干净.
这是Joe Duffy的一篇博客文章,解释了很多关于这些问题的内容:托管代码和异步异常加固.