c中的“看门狗”或沙盒系统

时间:2009-08-04 04:04:52

标签: .net timeout sandbox

我有一个我希望允许在给定时间内运行的函数,然后,如果它没有自行退出,则中止。 这样做的最佳方式是什么?

我想到的最好的方法是在另一个线程中运行它,等待超时让它死掉然后使用Thread.Abort()来杀死它(如果函数有错误的类型,这可能不起作用catch阻止)。另一种选择(一种我不知道如何工作的选择)将是某种先发制人的计时器,其中包括投掷。

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


编辑:我将要运行的功能没有任何系统来检查它是否应该取消而我不能(因为一定不能 )添加它。此外,这是一个各种各样的测试工具,所以我将杀死该功能的条件是它已经运行了。在那种情况下,我不能指望它做正确的事情。

8 个答案:

答案 0 :(得分:5)

对于类似这样的事情可能有点过分,但你可以研究一下你是否想要将托管该线程的任何内容加载到AppDomain中。 AppDomain本质上是一个.NET沙箱。

如果线程进入杂草,您可以杀死AppDomain。

答案 1 :(得分:2)

您要实施的是BackgroundWorkerBackgroundWorker可以执行后台操作,并提供通知后台取消操作的机制。

后台操作应定期检查传入的Cancel实例中的DoWorkEventArgs属性,如果值为true则优雅地自行终止。

可以通过在初始DoWorkEventArgs实例上调用CancelAsync方法来设置BackgroundWorker实例上的取消属性。

MSDN documentation中有一个很好的例子。另请参阅该页面底部的社区贡献和相关链接。


您可能还会发现此博客文章很有趣,它使用了Thread.Abort,我建议您尽量避免使用... C# Set method timeout using Generics

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

为什么功能不会退出?它产生了什么结果?

我的第一个尝试是让代码足够紧密并处理所有“卡住”的情况,这样你就不需要看门狗了 - 如果你在等待资源被释放,那就等待超时了,适当处理异常。

如果没有这个,我会尝试生成一个进程外的看门狗,根据需要做Process.Kill。这比Thread.Abort更有效 - 如果你想采用残酷的解决方案,为什么不一直走?

答案 4 :(得分:1)

我可能无法正确理解问题,但为什么不将逻辑放入函数本身?示例(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
}

答案 5 :(得分:1)

如果你不能轻易打断你的函数进程,你可能必须使用一个计时器来中止当前线程(它避免你在另一个线程中执行你的函数)。一旦当前线程中止,您将使用Thread.ResetAbort()重新插入此中止,并且您可以执行程序的其他步骤。

所以你可以使用类似这个的类

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();
        }
    }

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我知道这看起来有点矫枉过正,但技术上可以按照你想要的方式运作。拆分您正在处理的代码2.第一部分是经理,第二部分是执行者。

Executor(在您的情况下)可以是一个简单的命令行应用程序,其中包含您要测试的功能。此管理器应用程序此时执行的操作是使用Process(System.Diagnostics)类调用命令行应用程序。进程类的一种方法是WaitForExit,它将等待你的控制台应用程序退出。但是如果应用程序没有退出,您可以指定等待强制应用程序退出的时间。

使用它你应该能够得到你想要的东西