2

我有一个功能,我想允许它运行给定的时间长度,然后,如果它没有自行退出,则中止。做这个的最好方式是什么?

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

有没有更好的办法?某种简单的沙盒系统?


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

4

8 回答 8

5

对于这样的事情可能有点矫枉过正,但您可以查看是否要将托管该线程的任何内容加载到 AppDomain 中。AppDomain 本质上是一个 .NET 沙箱。

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

于 2009-08-04T04:32:03.937 回答
2

你想要实现的是一个BackgroundWorker. BackgroundWorker可以执行后台操作并提供用于通知该后台操作取消的机制。

后台操作应该定期检查Cancel传入DoWorkEventArgs实例的属性,如果值为 ,则优雅地杀死自己true

DoWorkEventArgs可以通过调用CancelAsync初始化实例上的方法来设置实例上的 Cancel 属性BackgroundWorker

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


您可能还会发现这篇博文很有趣,它使用 Thread.Abort,但我真的建议您避免使用... C# Set method timeout using Generics

于 2009-08-04T04:31:32.907 回答
1

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

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

于 2009-08-04T04:07:51.127 回答
1

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

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

除此之外,我会尝试产生一个进程外的看门狗,根据需要执行 Process.Kill 。这比 Thread.Abort 更有效——如果您要采用残酷的解决方案,为什么不一路走下去呢?

于 2009-08-04T04:31:59.553 回答
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
}
于 2009-08-04T04:39:53.953 回答
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();
        }
    }
于 2009-08-04T07:00:04.263 回答
0

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

于 2009-08-04T04:14:42.673 回答
0

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

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

使用这个你应该能够得到你想要的

于 2009-08-04T04:41:41.077 回答