Implementing RegEx Timeout in .NET 4

后端 未结 4 1697
情歌与酒
情歌与酒 2020-12-09 00:33

Platform: Silverlight 4, .NET 4

With the .NET 4.5 Developer preview the RegEx class has been enhanced to allow setting of a Timeout value which would prevent the Reg

相关标签:
4条回答
  • 2020-12-09 00:44

    I re-implemented the above code changing it in a way that I belive is more reliable.

        /// <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!
            } 
    
    0 讨论(0)
  • 2020-12-09 00:44

    The standard way to get a timeout on something that doesn't already come with the feature, is to simply start whatever you want to process on a separate thread, and then in your main thread, you use Thread.Join with the appropriate timeout.

    0 讨论(0)
  • 2020-12-09 00:48

    It is not that simple - but it can be done using two threads with the first doing the regex, the second killing the first thread if itruns too long. This is problematic in itself, though.

    0 讨论(0)
  • 2020-12-09 00:59

    Generic example:

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

    Usage:

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

    Update:

    As pointed out by Christian.K, the async thread will still continue running.

    Here is one where the thread will terminate:

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

    Update:

    Fixed above snippet to deal with exceptions correctly.

    0 讨论(0)
提交回复
热议问题