Implementing RegEx Timeout in .NET 4

本文关键字:NET in Timeout RegEx Implementing | 更新日期: 2023-09-27 18:25:49

平台:Silverlight 4,.NET 4

在.NET 4.5 Developer预览版中,RegEx类得到了增强,允许设置Timeout值,以防止RegEx引擎在模式匹配出现问题时挂起UI。

请求在.NET 4 Silverlight应用程序中实现类似功能的建议。

提前谢谢。

Implementing RegEx Timeout in .NET 4

一般示例:

public static R WithTimeout<R>(Func<R> proc, int duration)
{
  var wh = proc.BeginInvoke(null, null);
  if (wh.AsyncWaitHandle.WaitOne(duration))
  {
    return proc.EndInvoke(wh);
  }
  throw new TimeOutException();
}

用法:

var r = WithTimeout(() => regex.Match(foo), 1000);

更新:

正如Christian.K所指出的,异步线程仍将继续运行。

以下是线程将终止的位置:

public static R WithTimeout<R>(Func<R> proc, int duration)
{
  var reset = new AutoResetEvent(false);
  var r = default(R);
  Exception ex = null;
  var t = new Thread(() =>
  {
    try
    {
      r = proc();
    }
    catch (Exception e)
    {
      ex = e;
    }
    reset.Set();
  });
  t.Start();
  // not sure if this is really needed in general
  while (t.ThreadState != ThreadState.Running)
  {
    Thread.Sleep(0);
  }
  if (!reset.WaitOne(duration))
  {
    t.Abort();
    throw new TimeoutException();
  }
  if (ex != null)
  {
    throw ex;
  }
  return r;
}

更新:

修复了上面的代码段以正确处理异常。

这并没有那么简单,但它可以使用两个线程来完成,第一个线程执行regex,如果itrun太长,第二个线程会杀死第一个线程。不过,这本身就有问题。

我重新实现了上面的代码,以我认为更可靠的方式对其进行了更改。

    /// <summary>
    /// Executes function proc on a separate thread respecting the given timeout value.
    /// </summary>
    /// <typeparam name="R"></typeparam>
    /// <param name="proc">The function to execute.</param>
    /// <param name="timeout">The timeout duration.</param>
    /// <returns></returns>
    public static R ExecuteWithTimeout<R>(Func<R> proc, TimeSpan timeout) {
        var r = default(R); // init default return value
        Exception ex = null; // records inter-thread exception
        // define a thread to wrap 'proc'
        var t = new Thread(() => {
            try {
                r = proc();
                }
            catch (Exception e) {
                // this can get set to ThreadAbortException
                ex = e;
                Debug.WriteLine("Exception hit");
                }
            });
        t.Start(); // start running 'proc' thread wrapper
        // from docs: "The Start method does not return until the new thread has started running."
        if (t.Join(timeout) == false) {
            t.Abort(); // die evil thread!
            // Abort raises the ThreadAbortException
            int i = 0;
            while ((t.Join(1) == false) && (i < 20)) { // 20 ms wait possible here
                i++;
                }
            if (i >= 20) {
                // we didn't abort, might want to log this or take some other action
                // this can happen if you are doing something indefinitely hinky in a
                // finally block (cause the finally be will executed before the Abort 
                // completes.
                Debug.WriteLine("Abort didn't work as expected");
                }
            }
        if (ex != null) {
            throw ex; // oops
            }
        return r; // ah!
        } 

获得该功能尚未附带的超时的标准方法是,只需在一个单独的线程上启动您想要处理的任何内容,然后在主线程中使用thread.Join并设置适当的超时。