一种利用线程池线程执行任务, 并能够结束超时任务的方法 (.NET实现)
2008-03-25 12:37
961 查看
背景:
前些日子写了一个利用正则表达式来提取内容的程序,要求正则表达式可以灵活地配置,但事后在运行时发现一个问题:有的正则表达式写的效率低下,将CPU占用了100%,并且执行了很长时间也没有执行完,影响了其它任务的工作.于是想把执行正则表达式的代码放在一个可以在超时时自动中断的函数中.
首先想到的是每次使用线程System.Threading.Thread来定义一个新的线程,启动并执行,然后用ManualResetEvent等待它执行一段指定的时间,如果没有执行完,则调用该线程的Abort来中断它.
但大多数正则表达式执行的效率很高,这样每次都开一个线程会影响效率,于是想到了利用线程池线程来执行它,但在这儿遇到了难题,线程池线程只有在运行的时候才会利用Thread.CurrentThread来获得当前的线程(以便在超时时调用它的Abort方法),.
这种做法是很危险的时候,可能在超时之后,当我们调用Abort方法的那一瞬间,该线程已经完成了执行,并且又在执行其它任务了,于是中断了不该中断的任务.
思前想后,想到了利用两个ManualResetEvent来保证不在Abort时中断其它任务的方法:
代码:
delegate void Delegate();
/// <summary>
/// 执行指定的方法,如果在指定的时间之内没有完成,则中止
/// </summary>
/// <param name="func">任务过程</param>
/// <param name="timeSpan">超时时间</param>
/// <param name="timeoutCallback">如果超时,则调用该方法</param>
/// <returns>是否正确执行完毕</returns>
public static bool Call(Delegate func, TimeSpan timeSpan, Delegate timeoutCallback)
{
if (func == null)
throw new ArgumentNullException("func");
ManualResetEvent resetEvent = new ManualResetEvent(false);
ManualResetEvent waitThreadEvent = new ManualResetEvent(false);
Exception error = null;
Thread thread = null;
// 将任务加到线程当中
ThreadPool.QueueUserWorkItem(delegate {
thread = Thread.CurrentThread;
try { func(); }
catch (ThreadAbortException) { }
catch (Exception ex) { error = ex; }
resetEvent.Set();
waitThreadEvent.WaitOne(); // 每次线程执行结束都等待后续的处理逻辑
});
try
{
bool result = resetEvent.WaitOne(timeSpan, false); // 等待任务的结束
if (error != null) // 说明在执行过程中出现异常,直接抛出异常
throw error;
if (!result)
{
if (thread != null)
{
thread.Abort(); // 此时可以确保该线程没有开始运行新的任务
waitThreadEvent.Set();
}
if (timeoutCallback != null)
timeoutCallback();
}
return result;
}
finally
{
waitThreadEvent.Set(); // 最后确保释放线程池线程
}
}
前些日子写了一个利用正则表达式来提取内容的程序,要求正则表达式可以灵活地配置,但事后在运行时发现一个问题:有的正则表达式写的效率低下,将CPU占用了100%,并且执行了很长时间也没有执行完,影响了其它任务的工作.于是想把执行正则表达式的代码放在一个可以在超时时自动中断的函数中.
首先想到的是每次使用线程System.Threading.Thread来定义一个新的线程,启动并执行,然后用ManualResetEvent等待它执行一段指定的时间,如果没有执行完,则调用该线程的Abort来中断它.
但大多数正则表达式执行的效率很高,这样每次都开一个线程会影响效率,于是想到了利用线程池线程来执行它,但在这儿遇到了难题,线程池线程只有在运行的时候才会利用Thread.CurrentThread来获得当前的线程(以便在超时时调用它的Abort方法),.
这种做法是很危险的时候,可能在超时之后,当我们调用Abort方法的那一瞬间,该线程已经完成了执行,并且又在执行其它任务了,于是中断了不该中断的任务.
思前想后,想到了利用两个ManualResetEvent来保证不在Abort时中断其它任务的方法:
代码:
delegate void Delegate();
/// <summary>
/// 执行指定的方法,如果在指定的时间之内没有完成,则中止
/// </summary>
/// <param name="func">任务过程</param>
/// <param name="timeSpan">超时时间</param>
/// <param name="timeoutCallback">如果超时,则调用该方法</param>
/// <returns>是否正确执行完毕</returns>
public static bool Call(Delegate func, TimeSpan timeSpan, Delegate timeoutCallback)
{
if (func == null)
throw new ArgumentNullException("func");
ManualResetEvent resetEvent = new ManualResetEvent(false);
ManualResetEvent waitThreadEvent = new ManualResetEvent(false);
Exception error = null;
Thread thread = null;
// 将任务加到线程当中
ThreadPool.QueueUserWorkItem(delegate {
thread = Thread.CurrentThread;
try { func(); }
catch (ThreadAbortException) { }
catch (Exception ex) { error = ex; }
resetEvent.Set();
waitThreadEvent.WaitOne(); // 每次线程执行结束都等待后续的处理逻辑
});
try
{
bool result = resetEvent.WaitOne(timeSpan, false); // 等待任务的结束
if (error != null) // 说明在执行过程中出现异常,直接抛出异常
throw error;
if (!result)
{
if (thread != null)
{
thread.Abort(); // 此时可以确保该线程没有开始运行新的任务
waitThreadEvent.Set();
}
if (timeoutCallback != null)
timeoutCallback();
}
return result;
}
finally
{
waitThreadEvent.Set(); // 最后确保释放线程池线程
}
}
相关文章推荐
- C#利用Task实现任务超时多任务一起执行的方法
- .net让线程支持超时的方法实例和线程在执行结束后销毁的方法
- java利用线程池(ExecutorService)配合Callable和Future实现执行方法超时的阻断
- .net让线程支持超时的方法实例和线程在执行结束后销毁的方法
- Java实现等待所有子线程结束后再执行一段代码的方法
- 多线程线程池控制一个方法的并发量 限制只有5个线程执行任务
- 利用主线程与子线程间的消息通讯,实现任务处理队列.子线程中创建不会阻塞执行的窗口
- 等待线程池内线程执行完成的一种方法
- C#利用定时任务插件实现在后台线程中批量把动态文件生成静态文件方法
- Java多线程任务超时结束的5种实现方法
- 两个带有线程池的方法分别执行两组线程任务,第二个方法需要等待第一组任务执行完毕
- 线程任务超时结束方法
- .NET如何利用timer组件实现每天定时执行某项任务 .
- 利用动态代理+注解 实现子线程中执行方法
- CountDownLatch实现主线程等待所有子线程运行结束后再继续执行的实现
- 主线程等待子线程执行结束后再执行的实现方式
- Android中定时执行任务的3种实现方法
- Java:利用java Timer类实现定时执行任务的功能
- Android中定时执行任务的3种实现方法
- .NET中利用js让子窗体向父页面传值的实现方法