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

c语言中的“看门狗”或沙箱系统#

  •  2
  • BCS  · 技术社区  · 15 年前

    我有一个函数,我想让它运行一段给定的时间,然后,如果它自己没有退出,就中止。 最好的方法是什么?

    Thread.Abort() 杀死它(如果函数具有错误类型的 catch 块)。另一个选择(一个我不知道如何使其工作)将是某种抢占式计时器与抛出它。

    有更好的办法吗?某种简单的沙箱系统?


    编辑: 我将要运行的函数没有任何系统来检查它是否应该取消,我不能(如中所示) 不能 )加上它。此外,这是一个测试工具,所以我将终止函数的条件是它已经疯狂运行。在那种情况下,我不能指望它能做任何正确的事情。

    8 回复  |  直到 15 年前
        1
  •  5
  •   Michael Burr    15 年前

    这可能有点过分,但您可以研究是否要将承载该线程的任何东西加载到AppDomain中。AppDomain本质上是一个.NET沙盒。

    如果线程陷入杂草中,您可以直接杀死AppDomain。

        2
  •  2
  •   Eric Schoonover thSoft    15 年前

    您想要实现的是 BackgroundWorker . 这个 可以执行后台操作,并提供通知后台操作取消的机制。

    后台操作应定期检查 Cancel 传入的上的属性 DoWorkEventArgs 实例,并在值为 true .

    在服务器上设置Cancel属性 道夫坦格斯 实例可以通过调用 CancelAsync 幕后工作者 例如。

    这是一个很好的例子 MSDN documentation . 另请参见该页面底部的社区贡献和相关链接。


    你可能也会发现这篇博文很有趣,它使用了Thread.Abort,虽然我真的建议你避免。。。 C# Set method timeout using Generics

        3
  •  1
  •   Sam Harwell    15 年前

    尽你所能为这个问题找到一个合理的解决方案。异常不是流控制,线程中止更糟糕。也就是说,您可以在线程上运行它,并在超时后中止该线程。

    编辑:这里有一个措辞强硬但有效的解释,说明我是多么鼓励你找到另一个解决方案: http://tdanecker.blogspot.com/2007/08/do-never-ever-use-threadabort.html

        4
  •  1
  •   dbkk    15 年前

    为什么函数不退出?它产生了什么结果?

    我的第一个尝试是使代码足够紧凑,并处理所有“卡住”的情况,这样就不需要看门狗——如果您正在等待释放资源,请在等待时超时,并适当地处理异常。

    缺少这些,我会尝试生成一个进程外看门狗,根据需要执行进程。杀死。这比Thread.Abort更有效——如果您要采用残酷的解决方案,为什么不一直这样做呢?

        5
  •  1
  •   jkchong    15 年前

    我可能没有正确理解这个问题,但是为什么不将逻辑放入函数本身呢?示例(C#):

    public void someLongFunction()
    {
        DateTime start = DateTime.Now;
        while (DateTime.Now <= start.AddMinutes(5)) // assuming 5 mins run time
        {
             // long processing code here
             if (DateTime.Now > start.AddMinutes(5))
                 break;
             // more long processing code
        }
        // thread clean up etc. here
    }
    
        6
  •  1
  •   pierroz    15 年前

    因此,您可以使用类似于此的类

    using System.Threading;
    using System.Timers;
    
    namespace tools
    {
        public class ThreadAbortTimer
        {
            public ThreadAbortTimer(int timeout)
            {
                _CurrentThread = Thread.CurrentThread;
                _Timer = new System.Timers.Timer();
                _Timer.Elapsed += _Timer_Elapsed;
                _Timer.Interval = timeout;
                _Timer.Enable = true;
            }
    
            /// <summary>
            /// catch the timeout : if the current thread is still valid, it is aborted
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void _Timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                lock (typeof(ThreadAbortTimer))
                {
                    if (_CurrentThread != null)
                    {
                        _CurrentThread.Abort();
                        _CurrentThread = null;
                    }
                }
            }
    
            /// <summary>
            /// timer that will check if the process lasts less than 30 seconds
            /// </summary>
            private readonly System.Timers.Timer _Timer;
    
            /// <summary>
            /// current thread to abort if the process is longer than 30 sec
            /// </summary>
            private Thread _CurrentThread;
    
            /// <summary>
            /// stop the timer
            /// </summary>
            public void Disable()
            {
                lock (typeof(ThreadAbortTimer))
                {
                    _Timer.Enabled = false;
                    _CurrentThread = null;
                }
            }
    
            /// <summary>
            /// dispose the timer
            /// </summary>
            public void Dispose()
            {
                _Timer.Dispose();
            }
        }
    }
    

       using (var timer = new ThreadAbortTimer(timeout))
        {
            try
            {
                // the process you want to timeout
            }
            catch
            {
                timer.Disable();
                Thread.ResetAbort();
            }
        }
    
        7
  •  0
  •   Federico González    15 年前

    可以使用Thread.Join()限制线程执行。

        8
  •  0
  •   RC1140    15 年前

    我知道这似乎有些过分,但从技术上讲,它可以按照你想要的方式工作。将正在处理的代码拆分为2。第一部分是经理,第二部分是执行人。

    Executor(在您的例子中)可以是一个简单的命令行应用程序,具有您想要测试的任何功能。此时,manager应用程序所做的是使用Process(System.Diagnostics)类调用命令行应用程序。process类的方法之一是WaitForExit,它将等待控制台应用程序退出。但是如果应用程序没有退出,您可以指定在强制退出应用程序之前等待的时间。