代码之家  ›  专栏  ›  技术社区  ›  Raynos

C语言中的一种限时方法#

  •  13
  • Raynos  · 技术社区  · 14 年前

    我有一个游戏框架,其中有一个实现IBotInterface的机器人的列表。这些机器人是由用户定制的,唯一的限制是它们必须实现接口。

    然后,游戏在机器人程序中调用各种方法(希望是并行的)来处理各种事件,比如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);
                        }
                    }
                );
    

    如果能有一些

    try { 
     bot.NewGame(Info);
    } catch (TimeOutException) {
     // Tell bot off.
    } finally {
     // Compute things.
    }
    

    这样做的目的是优雅地处理人工智能谁有偶然的无限循环或正在花很长时间来计算。

    Class ActionThread {
        pulbic Thread thread { get; set; }
        public Queue<Action> queue { 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,从外观上看我可以这样做,但它看不出它会有什么帮助

    我希望不要期待恶意代码。试图杀死其他机器人线程不是赢得游戏的有效方法。我只是想给每一个机器人一秒钟的时间来计算,然后继续游戏流程,所以这里主要是期待缓慢或有缺陷的代码。

    我来看看CAS能做些什么,谢谢你们

    [更多编辑]

    我的头很痛,我好像再也不能思考或编码了。我正在为每个bot设置一个专用线程的消息传递系统,并将挂起/休眠这些线程

    6 回复  |  直到 14 年前
        1
  •  10
  •   Lasse V. Karlsen    14 年前

    不幸的是,没有100%安全的方法来终止线程 干净利落

    虽然你可以尝试很多方法,但是它们都有一些副作用和缺点,你可能会考虑。

    好好问吧 . 但是,如果您控制代码,这只是一种100%保证的方法。既然你不是,就不会是了。

    问题来了。

    • Thread.Abort ,则可能使appdomain处于不安全状态。可能存在文件未打开、网络或数据库连接未打开、内核对象处于无效状态等情况。

    让我们看看为什么合作也不是100%。

    假设有问题的线程经常需要调用你的库代码,以便在屏幕上绘图,或者诸如此类。您可以轻松地对这些方法进行检查,并抛出异常。

    然而,这个异常可能会被捕获,并被吞并。

    我已经说过你不能。

    然而,有一种方法可能有效。您可以将bot派生到自己的进程中,然后在进程超时时终止进程。这将为您提供更高的成功机会,因为至少操作系统会在进程死亡时处理它所管理的所有资源。当然,您可以让进程在系统上留下损坏的文件,所以它不是100%干净的。

    以下是Joe Duffy的一篇博客文章,解释了很多关于这些问题: Managed code and asynchronous exception hardening .

        2
  •  4
  •   Community CDub    8 年前

    .NET 4.0版 Task 在取消方面给你很大的灵活性。

    在代理中运行代理 你已经通过了 CancelationToken 变成,就像 this .

    here .

    根据反馈,我认为正确的答案是遵循以下计划:

    1. 限制使用CAS的AI,这样它就不能访问线程原语或乱七八糟地处理文件。

    2. 如果AI超时,记录它的弱移动,并给它一个短时间来调用回调。如果没有,就让线休眠到下一轮。如果它从未跳出,它将继续记录弱移动,直到进程将其作为后台线程而终止。

    3. 利润!

        3
  •  2
  •   Daniel Pratt    14 年前

    Thread 你自己,而不是依赖开始醒来。您可以通过线程。连接并且(不客气地)终止线程,如果必要的话,通过线程。中止.

        4
  •  2
  •   Dave White John Alexiou    14 年前

    This MSDN article 可能会为您提供一些关于如何使用TerminateThread函数更有效地终止失控线程的指导。

    你真的必须尝试所有这些事情,并向自己证明这可能是最好的解决办法。

    或者,如果这是一个竞争性的游戏,机器人作者必须公平地玩,你是否考虑过让游戏给每个机器人一个“回合令牌”,机器人必须在它想要调用的每个动作中呈现这个令牌,当游戏翻转时,它会给所有机器人一个新的令牌。这可能会让你现在只需要担心失控线程,而不是机器人谁需要花很长的时间在他们的回合。

    编辑

    只是为了增加一个地方让人们去看看 Security Permission Flag Enumerations 会让你知道从哪里开始。如果你移除了SecurityPermissionFlag.ControlThread控制线程权限(例如,仅给予代码执行权限,不包括ControlThread)您将删除它们的

    线程上的操作。

    我不知道有多少行动是无法进入的,但这将是一个有趣的周末演习,找出这个问题。

        5
  •  1
  •   Ben Voigt    14 年前

    EndInvoke 仅当任务成功完成时。

    粗略建议:

    var goodBots = new List<IBot>();
    var results = new IAsyncResult[Bots.Count];
    var events = new WaitHandle[Bots.Count];
    int i = 0;
    foreach (IBot bot in Bots) {
        NewGame del = bot.NewGame;
        results[i] = del.BeginInvoke(Info, null, null);
        events[i++] = r.AsyncWaitHandle;
    }
    WaitAll(events, RoundLimit);
    var goodBots = new List<IBot>();
    for( i = 0; i < events.Count; i++ ) {
        if (results[i].IsCompleted) {
            goodBots.Add(Bots[i]);
            EndInvoke(results[i]);
            results[i].Dispose();
        }
        else {
            WriteLine("bot " + i.ToString() + " eliminated by timeout.");
        }
    }
    Bots = goodBots;
    

        6
  •  0
  •   boo    14 年前

    另一种设计方案是允许每个bot都是自己的进程,然后使用IPC机制来交换数据。你通常可以终止一个进程而不产生任何可怕的影响。