在.NET 4中实现RegEx超时

时间:2012-02-27 06:00:36

标签: c# .net regex silverlight timeout

平台:Silverlight 4,.NET 4

使用.NET 4.5 Developer预览版,RegEx类已得到增强,允许设置Timeout值,如果模式匹配出现问题,将阻止RegEx引擎挂起UI。

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

提前致谢。

4 个答案:

答案 0 :(得分:11)

通用示例:

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

<强>更新

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

答案 1 :(得分:3)

这不是那么简单 - 但它可以使用两个线程完成,第一个执行正则表达式,第二个线程杀死第一个线程,如果它运行太长时间。但这本身就存在问题。

答案 2 :(得分:2)

我重新实现上面的代码,以我认为更可靠的方式更改它。

    /// <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!
        } 

答案 3 :(得分:1)

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