我有一个我希望允许在给定时间内运行的函数,然后,如果它没有自行退出,则中止。 这样做的最佳方式是什么?
我想到的最好的方法是在另一个线程中运行它,等待超时让它死掉然后使用Thread.Abort()
来杀死它(如果函数有错误的类型,这可能不起作用catch
阻止)。另一种选择(一种我不知道如何工作的选择)将是某种先发制人的计时器,其中包括投掷。
有更好的方法吗?某种简单的沙箱系统?
编辑:我将要运行的功能没有任何系统来检查它是否应该取消而我不能(因为一定不能 )添加它。此外,这是一个各种各样的测试工具,所以我将杀死该功能的条件是它已经运行了。在那种情况下,我不能指望它做正确的事情。
答案 0 :(得分:5)
对于类似这样的事情可能有点过分,但你可以研究一下你是否想要将托管该线程的任何内容加载到AppDomain中。 AppDomain本质上是一个.NET沙箱。
如果线程进入杂草,您可以杀死AppDomain。
答案 1 :(得分:2)
您要实施的是BackgroundWorker
。 BackgroundWorker
可以执行后台操作,并提供通知后台取消操作的机制。
后台操作应定期检查传入的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,它将等待你的控制台应用程序退出。但是如果应用程序没有退出,您可以指定等待强制应用程序退出的时间。
使用它你应该能够得到你想要的东西